summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 06:33:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 06:33:50 +0000
commitfe39ffb8b90ae4e002ed73fe98617cd590abb467 (patch)
treeb80e5956907d8aeaaffe4e4f0c068c0e6157ce8b /support
parentInitial commit. (diff)
downloadapache2-fe39ffb8b90ae4e002ed73fe98617cd590abb467.tar.xz
apache2-fe39ffb8b90ae4e002ed73fe98617cd590abb467.zip
Adding upstream version 2.4.56.upstream/2.4.56
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--support/.indent.pro54
-rw-r--r--support/Makefile.in89
-rw-r--r--support/NWGNUab330
-rw-r--r--support/NWGNUhtcacheclean253
-rw-r--r--support/NWGNUhtdbm252
-rw-r--r--support/NWGNUhtdigest251
-rw-r--r--support/NWGNUhtpasswd252
-rw-r--r--support/NWGNUhttxt2dbm251
-rw-r--r--support/NWGNUlogres258
-rw-r--r--support/NWGNUmakefile51
-rw-r--r--support/NWGNUrotlogs250
-rw-r--r--support/README65
-rw-r--r--support/SHA1/README.sha134
-rw-r--r--support/SHA1/convert-sha1.pl36
-rw-r--r--support/SHA1/htpasswd-sha1.pl22
-rw-r--r--support/SHA1/ldif-sha1.example19
-rw-r--r--support/ab.c2719
-rw-r--r--support/ab.dep37
-rw-r--r--support/ab.dsp106
-rw-r--r--support/ab.mak317
-rw-r--r--support/abs.dep37
-rw-r--r--support/abs.dsp144
-rw-r--r--support/abs.mak374
-rw-r--r--support/apachectl.in106
-rw-r--r--support/apxs.in801
-rwxr-xr-xsupport/check_forensic51
-rw-r--r--support/checkgid.c110
-rw-r--r--support/config.m4151
-rw-r--r--support/dbmmanage.in312
-rw-r--r--support/envvars-std.in28
-rw-r--r--support/fcgistarter.c220
-rw-r--r--support/fcgistarter.dep29
-rw-r--r--support/fcgistarter.dsp106
-rw-r--r--support/fcgistarter.mak317
-rw-r--r--support/htcacheclean.c1842
-rw-r--r--support/htcacheclean.dep37
-rw-r--r--support/htcacheclean.dsp106
-rw-r--r--support/htcacheclean.mak317
-rw-r--r--support/htdbm.c472
-rw-r--r--support/htdbm.dep58
-rw-r--r--support/htdbm.dsp110
-rw-r--r--support/htdbm.mak326
-rw-r--r--support/htdigest.c303
-rw-r--r--support/htdigest.dep27
-rw-r--r--support/htdigest.dsp106
-rw-r--r--support/htdigest.mak317
-rw-r--r--support/htpasswd.c524
-rw-r--r--support/htpasswd.dep57
-rw-r--r--support/htpasswd.dsp110
-rw-r--r--support/htpasswd.mak326
-rw-r--r--support/httxt2dbm.c335
-rw-r--r--support/httxt2dbm.dep26
-rw-r--r--support/httxt2dbm.dsp106
-rw-r--r--support/httxt2dbm.mak317
-rwxr-xr-xsupport/list_hooks.pl101
-rw-r--r--support/log_server_status.in76
-rw-r--r--support/logresolve.c329
-rw-r--r--support/logresolve.dep26
-rw-r--r--support/logresolve.dsp106
-rw-r--r--support/logresolve.mak317
-rw-r--r--support/logresolve.pl.in225
-rw-r--r--support/passwd_common.c344
-rw-r--r--support/passwd_common.h128
-rw-r--r--support/phf_abuse_log.cgi.in38
-rw-r--r--support/rotatelogs.c810
-rw-r--r--support/rotatelogs.dep28
-rw-r--r--support/rotatelogs.dsp106
-rw-r--r--support/rotatelogs.mak317
-rw-r--r--support/split-logfile.in69
-rw-r--r--support/suexec.c685
-rw-r--r--support/suexec.h109
-rw-r--r--support/win32/ApacheMonitor.c1671
-rw-r--r--support/win32/ApacheMonitor.dep18
-rw-r--r--support/win32/ApacheMonitor.dsp143
-rw-r--r--support/win32/ApacheMonitor.h78
-rw-r--r--support/win32/ApacheMonitor.icobin0 -> 1078 bytes
-rw-r--r--support/win32/ApacheMonitor.mak309
-rw-r--r--support/win32/ApacheMonitor.manifest10
-rw-r--r--support/win32/ApacheMonitor.rc103
-rw-r--r--support/win32/apache_header.bmpbin0 -> 6498 bytes
-rw-r--r--support/win32/aprun.icobin0 -> 318 bytes
-rw-r--r--support/win32/apstop.icobin0 -> 318 bytes
-rw-r--r--support/win32/srun.bmpbin0 -> 246 bytes
-rw-r--r--support/win32/sstop.bmpbin0 -> 246 bytes
-rw-r--r--support/win32/wintty.c374
-rw-r--r--support/win32/wintty.dep5
-rw-r--r--support/win32/wintty.dsp106
-rw-r--r--support/win32/wintty.mak317
88 files changed, 21202 insertions, 0 deletions
diff --git a/support/.indent.pro b/support/.indent.pro
new file mode 100644
index 0000000..a9fbe9f
--- /dev/null
+++ b/support/.indent.pro
@@ -0,0 +1,54 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
+-TBUFF
+-TFILE
+-TTRANS
+-TUINT4
+-T_trans
+-Tallow_options_t
+-Tapache_sfio
+-Tarray_header
+-Tbool_int
+-Tbuf_area
+-Tbuff_struct
+-Tbuffy
+-Tcmd_how
+-Tcmd_parms
+-Tcommand_rec
+-Tcommand_struct
+-Tconn_rec
+-Tcore_dir_config
+-Tcore_server_config
+-Tdir_maker_func
+-Tevent
+-Tglobals_s
+-Thandler_func
+-Thandler_rec
+-Tjoblist_s
+-Tlisten_rec
+-Tmerger_func
+-Tmode_t
+-Tmodule
+-Tmodule_struct
+-Tmutex
+-Tn_long
+-Tother_child_rec
+-Toverrides_t
+-Tparent_score
+-Tpid_t
+-Tpiped_log
+-Tpool
+-Trequest_rec
+-Trequire_line
+-Trlim_t
+-Tscoreboard
+-Tsemaphore
+-Tserver_addr_rec
+-Tserver_rec
+-Tserver_rec_chain
+-Tshort_score
+-Ttable
+-Ttable_entry
+-Tthread
+-Tu_wide_int
+-Tvtime_t
+-Twide_int
diff --git a/support/Makefile.in b/support/Makefile.in
new file mode 100644
index 0000000..c7d7687
--- /dev/null
+++ b/support/Makefile.in
@@ -0,0 +1,89 @@
+DISTCLEAN_TARGETS = apxs apachectl dbmmanage log_server_status \
+ logresolve.pl phf_abuse_log.cgi split-logfile envvars-std
+
+CLEAN_TARGETS = suexec
+
+bin_PROGRAMS = htpasswd htdigest htdbm ab logresolve httxt2dbm
+sbin_PROGRAMS = htcacheclean rotatelogs $(NONPORTABLE_SUPPORT)
+TARGETS = $(bin_PROGRAMS) $(sbin_PROGRAMS)
+
+PROGRAM_LDADD = $(UTIL_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS) $(AP_LIBS)
+PROGRAM_DEPENDENCIES =
+
+include $(top_builddir)/build/rules.mk
+
+install:
+ @test -d $(DESTDIR)$(bindir) || $(MKINSTALLDIRS) $(DESTDIR)$(bindir)
+ @test -d $(DESTDIR)$(sbindir) || $(MKINSTALLDIRS) $(DESTDIR)$(sbindir)
+ @test -d $(DESTDIR)$(libexecdir) || $(MKINSTALLDIRS) $(DESTDIR)$(libexecdir)
+ @cp -p $(top_builddir)/server/httpd.exp $(DESTDIR)$(libexecdir)
+ @for i in apxs dbmmanage; do \
+ if test -f "$(builddir)/$$i"; then \
+ cp -p $$i $(DESTDIR)$(bindir); \
+ chmod 755 $(DESTDIR)$(bindir)/$$i; \
+ fi ; \
+ done
+ @for i in apachectl; do \
+ if test -f "$(builddir)/$$i"; then \
+ cp -p $$i $(DESTDIR)$(sbindir); \
+ chmod 755 $(DESTDIR)$(sbindir)/$$i; \
+ fi ; \
+ done
+ @if test -f "$(builddir)/envvars-std"; then \
+ cp -p envvars-std $(DESTDIR)$(sbindir); \
+ if test ! -f $(DESTDIR)$(sbindir)/envvars; then \
+ cp -p envvars-std $(DESTDIR)$(sbindir)/envvars ; \
+ fi ; \
+ fi
+
+htpasswd.lo: passwd_common.h
+passwd_common.lo: passwd_common.h
+htpasswd_OBJECTS = htpasswd.lo passwd_common.lo
+htpasswd: $(htpasswd_OBJECTS)
+ $(LINK) $(htpasswd_LTFLAGS) $(htpasswd_OBJECTS) $(PROGRAM_LDADD) $(CRYPT_LIBS)
+
+htdigest_OBJECTS = htdigest.lo
+htdigest: $(htdigest_OBJECTS)
+ $(LINK) $(htdigest_LTFLAGS) $(htdigest_OBJECTS) $(PROGRAM_LDADD)
+
+rotatelogs_OBJECTS = rotatelogs.lo
+rotatelogs: $(rotatelogs_OBJECTS)
+ $(LINK) $(rotatelogs_LTFLAGS) $(rotatelogs_OBJECTS) $(PROGRAM_LDADD)
+
+logresolve_OBJECTS = logresolve.lo
+logresolve: $(logresolve_OBJECTS)
+ $(LINK) $(logresolve_LTFLAGS) $(logresolve_OBJECTS) $(PROGRAM_LDADD)
+
+htdbm.lo: passwd_common.h
+htdbm_OBJECTS = htdbm.lo passwd_common.lo
+htdbm: $(htdbm_OBJECTS)
+ $(LINK) $(htdbm_LTFLAGS) $(htdbm_OBJECTS) $(PROGRAM_LDADD) $(CRYPT_LIBS)
+
+ab_OBJECTS = ab.lo
+ab_LDADD = $(PROGRAM_LDADD) $(MATH_LIBS) $(ab_LIBS)
+ab.lo: ab.c
+ $(LIBTOOL) --mode=compile $(CC) $(ab_CFLAGS) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \
+ $(ALL_INCLUDES) $(PICFLAGS) $(LTCFLAGS) -c $< && touch $@
+ab: $(ab_OBJECTS)
+ $(LIBTOOL) --mode=link $(CC) $(ALL_CFLAGS) $(PILDFLAGS) \
+ $(LT_LDFLAGS) $(ALL_LDFLAGS) -o $@ $(ab_LTFLAGS) $(ab_OBJECTS) $(ab_LDADD)
+
+checkgid_OBJECTS = checkgid.lo
+checkgid: $(checkgid_OBJECTS)
+ $(LINK) $(checkgid_LTFLAGS) $(checkgid_OBJECTS) $(PROGRAM_LDADD)
+
+suexec_OBJECTS = suexec.lo
+suexec: $(suexec_OBJECTS)
+ $(LINK) $(suexec_OBJECTS)
+
+htcacheclean_OBJECTS = htcacheclean.lo
+htcacheclean: $(htcacheclean_OBJECTS)
+ $(LINK) $(htcacheclean_LTFLAGS) $(htcacheclean_OBJECTS) $(PROGRAM_LDADD)
+
+httxt2dbm_OBJECTS = httxt2dbm.lo
+httxt2dbm: $(httxt2dbm_OBJECTS)
+ $(LINK) $(httxt2dbm_LTFLAGS) $(httxt2dbm_OBJECTS) $(PROGRAM_LDADD)
+
+fcgistarter_OBJECTS = fcgistarter.lo
+fcgistarter: $(fcgistarter_OBJECTS)
+ $(LINK) $(fcgistarter_LTFLAGS) $(fcgistarter_OBJECTS) $(PROGRAM_LDADD)
diff --git a/support/NWGNUab b/support/NWGNUab
new file mode 100644
index 0000000..c22b6c1
--- /dev/null
+++ b/support/NWGNUab
@@ -0,0 +1,330 @@
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# build this level's files
+#
+# Make sure all needed macro's are defined
+#
+
+ifeq "$(WITH_ABS)" "1"
+
+ifeq "$(USE_NTLS)" "1"
+SSL_INC = $(NTLSSDK)/inc
+SSL_LIB = $(NTLSSDK)/imp
+SSL_BIN = $(NTLSSDK)/bin
+SSL_APP = $(NTLSSDK)/apps
+ifneq "$(wildcard $(SSL_INC)/openssl/opensslv.h)" "$(SSL_INC)/openssl/opensslv.h"
+$(warning '$(NTLSSDK)' does NOT point to a valid NTLS SDK!)
+endif
+else
+SSL_INC = $(OSSLSDK)/outinc_nw_libc
+SSL_LIB = $(OSSLSDK)/out_nw_libc
+SSL_BIN = $(OSSLSDK)/out_nw_libc
+SSL_APP = $(OSSLSDK)/apps
+ifneq "$(wildcard $(SSL_INC)/openssl/opensslv.h)" "$(SSL_INC)/openssl/opensslv.h"
+$(warning '$(OSSLSDK)' does NOT point to a valid OpenSSL SDK!)
+endif
+endif
+ifeq "$(wildcard $(SSL_INC)/openssl/opensslv.h)" "$(SSL_INC)/openssl/opensslv.h"
+HAVE_OPENSSL = 1
+endif
+
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+ifdef HAVE_OPENSSL
+XINCDIRS += \
+ $(SSL_INC) \
+ $(SSL_INC)/openssl \
+ $(EOLIST)
+endif
+
+XINCDIRS += \
+ $(NWOS) \
+ $(AP_WORK)/include \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+ifdef HAVE_OPENSSL
+XDEFINES += \
+ -DHAVE_OPENSSL \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ -l $(SSL_LIB) \
+ $(EOLIST)
+endif
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+ifdef HAVE_OPENSSL
+NLM_NAME = abs
+else
+NLM_NAME = ab
+endif
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Benchmark Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = $(NLM_NAME)
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+#NLM_SCREEN_NAME = Apache Bench
+NLM_SCREEN_NAME = DEFAULT
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 65536
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/$(NLM_NAME).nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/ab.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+ifdef HAVE_OPENSSL
+ifneq "$(USE_NTLS)" "1"
+FILES_nlm_libs += \
+ $(SSL_LIB)/crypto.lib \
+ $(SSL_LIB)/ssl.lib \
+ $(EOLIST)
+endif
+endif
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+ifdef HAVE_OPENSSL
+ifeq "$(USE_NTLS)" "1"
+FILES_nlm_modules += ntls \
+ $(EOLIST)
+endif
+endif
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+# Don't link with Winsock if standard sockets are being used
+ifneq "$(USE_STDSOCKETS)" "1"
+FILES_nlm_Ximports += @ws2nlm.imp \
+ $(EOLIST)
+endif
+
+ifdef HAVE_OPENSSL
+ifeq "$(USE_NTLS)" "1"
+FILES_nlm_Ximports += @ntls.imp \
+ $(EOLIST)
+else
+FILES_nlm_Ximports += \
+ GetProcessSwitchCount \
+ RunningProcess \
+ GetSuperHighResolutionTimer \
+ $(EOLIST)
+endif
+endif
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)/build/NWGNUtail.inc
+
diff --git a/support/NWGNUhtcacheclean b/support/NWGNUhtcacheclean
new file mode 100644
index 0000000..f813527
--- /dev/null
+++ b/support/NWGNUhtcacheclean
@@ -0,0 +1,253 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(STDMOD)/cache \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(APR)/misc/netware \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = htcacheclean
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) HT Disk Cache Cleanup Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = htcacheclean
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = DEFAULT
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/htcacheclean.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/htcacheclean.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/NWGNUhtdbm b/support/NWGNUhtdbm
new file mode 100644
index 0000000..5a2f739
--- /dev/null
+++ b/support/NWGNUhtdbm
@@ -0,0 +1,252 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(NWOS) \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = htdbm
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) HT Database Management Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = htdbm
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = htdbm Password Management
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/htdbm.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/htdbm.o \
+ $(OBJDIR)/passwd_common.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/NWGNUhtdigest b/support/NWGNUhtdigest
new file mode 100644
index 0000000..fa5abc1
--- /dev/null
+++ b/support/NWGNUhtdigest
@@ -0,0 +1,251 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(NWOS) \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = htdigest
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) HT Digest Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = htdigest
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = Digest Password Management
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/htdigest.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/htdigest.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/NWGNUhtpasswd b/support/NWGNUhtpasswd
new file mode 100644
index 0000000..124895b
--- /dev/null
+++ b/support/NWGNUhtpasswd
@@ -0,0 +1,252 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(NWOS) \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = htpasswd
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) HT Password Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = htpasswd
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = htpasswd Password Management
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/htpasswd.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/htpasswd.o \
+ $(OBJDIR)/passwd_common.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/NWGNUhttxt2dbm b/support/NWGNUhttxt2dbm
new file mode 100644
index 0000000..c33532d
--- /dev/null
+++ b/support/NWGNUhttxt2dbm
@@ -0,0 +1,251 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(NWOS) \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = httxt2dbm
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) HT Text to DBM Conversion Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = httxt2dbm
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = httxt2dbm Conversion Utility
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/httxt2dbm.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/httxt2dbm.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/NWGNUlogres b/support/NWGNUlogres
new file mode 100644
index 0000000..33ccfe0
--- /dev/null
+++ b/support/NWGNUlogres
@@ -0,0 +1,258 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(NWOS) \
+ $(AP_WORK)/include \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = logres
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Logresolve Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = logres
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = Log Resolve
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 65536
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/logres.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/logresolve.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+# Don't link with Winsock if standard sockets are being used
+ifndef USE_STDSOCKETS
+FILES_nlm_Ximports += @ws2nlm.imp \
+ $(EOLIST)
+endif
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/NWGNUmakefile b/support/NWGNUmakefile
new file mode 100644
index 0000000..9cb5d1d
--- /dev/null
+++ b/support/NWGNUmakefile
@@ -0,0 +1,51 @@
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)/build/NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/ab.nlm \
+ $(OBJDIR)/htpasswd.nlm \
+ $(OBJDIR)/htdigest.nlm \
+ $(OBJDIR)/htdbm.nlm \
+ $(OBJDIR)/htcacheclean.nlm \
+ $(OBJDIR)/httxt2dbm.nlm \
+ $(OBJDIR)/logres.nlm \
+ $(OBJDIR)/rotlogs.nlm \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/bin/)
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/support/NWGNUrotlogs b/support/NWGNUrotlogs
new file mode 100644
index 0000000..fb9e3ae
--- /dev/null
+++ b/support/NWGNUrotlogs
@@ -0,0 +1,250 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(NWOS) \
+ $(APR)/include \
+ $(APR)/misc/netware \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = rotlogs
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Log Rotation Utility for NetWare
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = rotlogs
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = DEFAULT
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 98304
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/rotlogs.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/rotatelogs.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
diff --git a/support/README b/support/README
new file mode 100644
index 0000000..09dadb2
--- /dev/null
+++ b/support/README
@@ -0,0 +1,65 @@
+Support files:
+
+ab
+ ABuse your server with this benchmarker. Rudimentary
+ command line testing tool.
+
+apachectl
+ Apache run-time Control script. To facilitate the
+ administrator and/or your rc.d scripts to control the
+ functioning of the Apache httpd daemon.
+
+apxs
+ APache eXtenSion tool. Eases building and installing
+ DSO style modules.
+
+dbmmanage
+ Create and update user authentication files in the faster
+ DBM format used by mod_auth_db.
+
+htcacheclean
+ Keep the size of mod_cache_disk store within a certain limit.
+
+htdigest
+ Create and update user authentication files used in
+ DIGEST authentification. See mod_auth_digest.
+
+htpasswd
+ Create and update user authentication files used in
+ BASIC authentification. I.e. the htpasswd files.
+ See mod_auth.
+
+httpd.8
+ General apache man page.
+
+log_server_status
+ This script is designed to be run at a frequent interval by something
+ like cron. It connects to the server and downloads the status
+ information. It reformats the information to a single line and logs
+ it to a file.
+
+logresolve
+ resolve hostnames for IP-adresses in Apache logfiles
+
+phf_abuse_log.cgi
+ This script can be used to detect people trying to abuse an ancient
+ and long plugged security hole which existed in a CGI script distributed
+ with Apache 1.0.3 and earlier versions.
+
+rotatelogs
+ rotate Apache logs without having to kill the server.
+
+split-logfile
+ This script will take a combined virtual hosts access
+ log file and break its contents into separate files.
+
+suexec
+ Switch User For Exec. Used internally by apache,
+ see the document `Apache suEXEC Support'
+ under http://www.apache.org/docs/suexec.html .
+
+SHA1
+ This directory includes some utilities to allow Apache 1.3.6 to
+ recognize passwords in SHA1 format, as used by Netscape web
+ servers. It is not installed by default.
+
diff --git a/support/SHA1/README.sha1 b/support/SHA1/README.sha1
new file mode 100644
index 0000000..3998e1f
--- /dev/null
+++ b/support/SHA1/README.sha1
@@ -0,0 +1,34 @@
+This directory includes some utilities to allow Apache 1.3.6 to
+recognize passwords in SHA1 format, as used by Netscape web servers.
+
+From Netscape's admin interface, export the password database to an
+ldif file and then use convert.pl in this distribution to generate
+apache style password files.
+
+Note: SHA1 support is useful for migration purposes, but is less
+ secure than Apache's password format, since Apache's (MD5)
+ password format uses a random eight character salt to generate
+ one of many possible hashes for the same password. Netscape
+ uses plain SHA1 without a salt, so the same password
+ will always generate the same hash, making it easier
+ to break since the search space is smaller.
+
+This code was contributed by Clinton Wong <clintdw@netcom.com>.
+
+README.sha1
+ this file
+
+convert-sha1.pl
+ takes an ldif dump from Netscape's web server on
+ standard in, outputs apache htpasswd format on standard out.
+
+ Usage: convert.pl < ldif > passwords
+
+htpasswd-sha1.pl
+ perl script to generate entries in apache htpasswd format.
+
+ Usage: htpasswd-sha1.pl some_user some_password
+
+ldif-sha1.example
+ sample ldif dump with one sha1 password and one crypt password.
+
diff --git a/support/SHA1/convert-sha1.pl b/support/SHA1/convert-sha1.pl
new file mode 100644
index 0000000..3522802
--- /dev/null
+++ b/support/SHA1/convert-sha1.pl
@@ -0,0 +1,36 @@
+#!/usr/bin/perl -w
+use strict;
+
+# This is public domain code. Do whatever you want with it.
+# It was originally included in Clinton Wong's Apache 1.3.6 SHA1/ldif
+# patch distribution as sample code for converting accounts from
+# ldif format (as used by Netscape web servers) to Apache password format.
+
+my $uid='';
+my $passwd='';
+
+while (my $line = <>) {
+ chomp $line;
+ if ( $line =~ /uid:\s*(.+)/) { $uid = $1 }
+ if ( $line =~ /userpassword:\s*(\{\w+\}.+)/) {
+ $passwd = $1;
+ $passwd =~ s/^\{crypt\}//i; # Apache stores crypt without a magic string
+ }
+
+ if (length($line)==0) {
+
+ if (length $uid and length $passwd) {
+ print $uid, ':', $passwd, "\n";
+ } # output if we have something to print
+
+ $uid = '';
+ $passwd = '';
+
+ } # if newline
+} # while something to read
+
+# handle last entry if there isn't a newline before EOF
+ if (length $uid and length $passwd) {
+ print $uid, ':', $passwd, "\n";
+}
+
diff --git a/support/SHA1/htpasswd-sha1.pl b/support/SHA1/htpasswd-sha1.pl
new file mode 100644
index 0000000..a9dad11
--- /dev/null
+++ b/support/SHA1/htpasswd-sha1.pl
@@ -0,0 +1,22 @@
+#!/usr/bin/perl -w
+use strict;
+#
+# Utility which takes a username and password
+# on the command line and generates a username
+# sha1-encrytped password on the stdout.
+#
+# Typical usage:
+# ./htpasswd-sha1.pl dirkx MySecret >> sha1-passwd
+#
+# This is public domain code. Do whatever you want with it.
+# It was originally included in Clinton Wong's Apache 1.3.6 SHA1/ldif
+# patch distribution as sample code for generating entries for
+# Apache password files using SHA1.
+
+use MIME::Base64; # http://www.cpan.org/modules/by-module/MIME/
+use Digest::SHA1; # http://www.cpan.org/modules/by-module/MD5/
+
+if ($#ARGV!=1) { die "Usage $0: user password\n" }
+
+print $ARGV[0], ':{SHA}', encode_base64( Digest::SHA1::sha1($ARGV[1]) );
+
diff --git a/support/SHA1/ldif-sha1.example b/support/SHA1/ldif-sha1.example
new file mode 100644
index 0000000..b8fe917
--- /dev/null
+++ b/support/SHA1/ldif-sha1.example
@@ -0,0 +1,19 @@
+dn: cn=someuser
+cn: someuser
+sn: someuser
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: someuser
+userpassword: {SHA}GvF+c3IdvgxAARuC7Uuxp9vjzik=
+
+dn: cn=anotheruser
+cn: anotheruser
+sn: anotheruser
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: anotheruser
+userpassword: {crypt}eFnp.4sz5XnH6
diff --git a/support/ab.c b/support/ab.c
new file mode 100644
index 0000000..3aa2660
--- /dev/null
+++ b/support/ab.c
@@ -0,0 +1,2719 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ** This program is based on ZeusBench V1.0 written by Adam Twiss
+ ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/
+ **
+ ** This software is provided "as is" and any express 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
+ ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special,
+ ** exemplary, or consequential damaged (including, but not limited to,
+ ** procurement of substitute good or services; loss of use, data, or profits;
+ ** or business interruption) however caused and on 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.
+ **
+ */
+
+/*
+ ** HISTORY:
+ ** - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996
+ ** with input from Mike Belshe <mbelshe@netscape.com> and
+ ** Michael Campanella <campanella@stevms.enet.dec.com>
+ ** - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997
+ ** - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998
+ ** - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998
+ ** - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999
+ ** - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999
+ ** Version 1.3d
+ ** - Increased version number - as some of the socket/error handling has
+ ** fundamentally changed - and will give fundamentally different results
+ ** in situations where a server is dropping requests. Therefore you can
+ ** no longer compare results of AB as easily. Hence the inc of the version.
+ ** They should be closer to the truth though. Sander & <dirkx@covalent.net>, End 2000.
+ ** - Fixed proxy functionality, added median/mean statistics, added gnuplot
+ ** output option, added _experimental/rudimentary_ SSL support. Added
+ ** confidence guestimators and warnings. Sander & <dirkx@covalent.net>, End 2000
+ ** - Fixed serious int overflow issues which would cause realistic (longer
+ ** than a few minutes) run's to have wrong (but believable) results. Added
+ ** trapping of connection errors which influenced measurements.
+ ** Contributed by Sander Temme, Early 2001
+ ** Version 1.3e
+ ** - Changed timeout behavior during write to work whilst the sockets
+ ** are filling up and apr_write() does writes a few - but not all.
+ ** This will potentially change results. <dirkx@webweaving.org>, April 2001
+ ** Version 2.0.36-dev
+ ** Improvements to concurrent processing:
+ ** - Enabled non-blocking connect()s.
+ ** - Prevent blocking calls to apr_socket_recv() (thereby allowing AB to
+ ** manage its entire set of socket descriptors).
+ ** - Any error returned from apr_socket_recv() that is not EAGAIN or EOF
+ ** is now treated as fatal.
+ ** Contributed by Aaron Bannert, April 24, 2002
+ **
+ ** Version 2.0.36-2
+ ** Internalized the version string - this string is part
+ ** of the Agent: header and the result output.
+ **
+ ** Version 2.0.37-dev
+ ** Adopted SSL code by Madhu Mathihalli <madhusudan_mathihalli@hp.com>
+ ** [PATCH] ab with SSL support Posted Wed, 15 Aug 2001 20:55:06 GMT
+ ** Introduces four 'if (int == value)' tests per non-ssl request.
+ **
+ ** Version 2.0.40-dev
+ ** Switched to the new abstract pollset API, allowing ab to
+ ** take advantage of future apr_pollset_t scalability improvements.
+ ** Contributed by Brian Pane, August 31, 2002
+ **
+ ** Version 2.3
+ ** SIGINT now triggers output_results().
+ ** Contributed by colm, March 30, 2006
+ **/
+
+/* Note: this version string should start with \d+[\d\.]* and be a valid
+ * string for an HTTP Agent: header when prefixed with 'ApacheBench/'.
+ * It should reflect the version of AB - and not that of the apache server
+ * it happens to accompany. And it should be updated or changed whenever
+ * the results are no longer fundamentally comparable to the results of
+ * a previous version of ab. Either due to a change in the logic of
+ * ab - or to due to a change in the distribution it is compiled with
+ * (such as an APR change in for example blocking).
+ */
+#define AP_AB_BASEREVISION "2.3"
+
+/*
+ * BUGS:
+ *
+ * - uses strcpy/etc.
+ * - has various other poor buffer attacks related to the lazy parsing of
+ * response headers from the server
+ * - doesn't implement much of HTTP/1.x, only accepts certain forms of
+ * responses
+ * - (performance problem) heavy use of strstr shows up top in profile
+ * only an issue for loopback usage
+ */
+
+/* -------------------------------------------------------------------- */
+
+#if 'A' != 0x41
+/* Hmmm... This source code isn't being compiled in ASCII.
+ * In order for data that flows over the network to make
+ * sense, we need to translate to/from ASCII.
+ */
+#define NOT_ASCII
+#endif
+
+/* affects include files on Solaris */
+#define BSD_COMP
+
+#include "apr.h"
+#include "apr_signal.h"
+#include "apr_strings.h"
+#include "apr_network_io.h"
+#include "apr_file_io.h"
+#include "apr_time.h"
+#include "apr_getopt.h"
+#include "apr_general.h"
+#include "apr_lib.h"
+#include "apr_portable.h"
+#include "ap_release.h"
+#include "apr_poll.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "apr_base64.h"
+#ifdef NOT_ASCII
+#include "apr_xlate.h"
+#endif
+#if APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h> /* for getpid() */
+#endif
+
+#if !defined(WIN32) && !defined(NETWARE)
+#include "ap_config_auto.h"
+#endif
+
+#include <math.h>
+#if APR_HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if APR_HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if defined(HAVE_OPENSSL)
+
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#define USE_SSL
+
+#define SK_NUM(x) sk_X509_num(x)
+#define SK_VALUE(x,y) sk_X509_value(x,y)
+typedef STACK_OF(X509) X509_STACK_TYPE;
+
+#if defined(_MSC_VER) && !defined(LIBRESSL_VERSION_NUMBER)
+/* The following logic ensures we correctly glue FILE* within one CRT used
+ * by the OpenSSL library build to another CRT used by the ab.exe build.
+ * This became especially problematic with Visual Studio 2015.
+ */
+#include <openssl/applink.c>
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x00909000)
+#define AB_SSL_METHOD_CONST const
+#else
+#define AB_SSL_METHOD_CONST
+#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x0090707f)
+#define AB_SSL_CIPHER_CONST const
+#else
+#define AB_SSL_CIPHER_CONST
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+#define HAVE_TLSV1_X
+#endif
+#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name)
+#define HAVE_TLSEXT
+#endif
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2060000f
+#define SSL_CTRL_SET_MIN_PROTO_VERSION 123
+#define SSL_CTRL_SET_MAX_PROTO_VERSION 124
+#define SSL_CTX_set_min_proto_version(ctx, version) \
+ SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
+#define SSL_CTX_set_max_proto_version(ctx, version) \
+ SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#ifdef TLS1_3_VERSION
+#define MAX_SSL_PROTO TLS1_3_VERSION
+#else
+#define MAX_SSL_PROTO TLS1_2_VERSION
+#endif
+#ifndef OPENSSL_NO_SSL3
+#define MIN_SSL_PROTO SSL3_VERSION
+#else
+#define MIN_SSL_PROTO TLS1_VERSION
+#endif
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+
+#endif /* HAVE_OPENSSL */
+
+/* ------------------- DEFINITIONS -------------------------- */
+
+#ifndef LLONG_MAX
+#define AB_MAX APR_INT64_C(0x7fffffffffffffff)
+#else
+#define AB_MAX LLONG_MAX
+#endif
+
+/* maximum number of requests on a time limited test */
+#define MAX_REQUESTS (INT_MAX > 50000 ? 50000 : INT_MAX)
+
+/* connection state
+ * don't add enums or rearrange or otherwise change values without
+ * visiting set_conn_state()
+ */
+typedef enum {
+ STATE_UNCONNECTED = 0,
+ STATE_CONNECTING, /* TCP connect initiated, but we don't
+ * know if it worked yet
+ */
+ STATE_CONNECTED, /* we know TCP connect completed */
+ STATE_READ
+} connect_state_e;
+
+#define CBUFFSIZE (8192)
+
+struct connection {
+ apr_pool_t *ctx;
+ apr_socket_t *aprsock;
+ apr_pollfd_t pollfd;
+ int state;
+ apr_size_t read; /* amount of bytes read */
+ apr_size_t bread; /* amount of body read */
+ apr_size_t rwrite, rwrote; /* keep pointers in what we write - across
+ * EAGAINs */
+ apr_size_t length; /* Content-Length value used for keep-alive */
+ char cbuff[CBUFFSIZE]; /* a buffer to store server response header */
+ int cbx; /* offset in cbuffer */
+ int keepalive; /* non-zero if a keep-alive request */
+ int gotheader; /* non-zero if we have the entire header in
+ * cbuff */
+ apr_time_t start, /* Start of connection */
+ connect, /* Connected, start writing */
+ endwrite, /* Request written */
+ beginread, /* First byte of input */
+ done; /* Connection closed */
+
+ int socknum;
+#ifdef USE_SSL
+ SSL *ssl;
+#endif
+};
+
+struct data {
+ apr_time_t starttime; /* start time of connection */
+ apr_interval_time_t waittime; /* between request and reading response */
+ apr_interval_time_t ctime; /* time to connect */
+ apr_interval_time_t time; /* time for connection */
+};
+
+#define ap_min(a,b) (((a)<(b))?(a):(b))
+#define ap_max(a,b) (((a)>(b))?(a):(b))
+#define ap_round_ms(a) ((apr_time_t)((a) + 500)/1000)
+#define ap_double_ms(a) ((double)(a)/1000.0)
+#define MAX_CONCURRENCY 20000
+
+/* --------------------- GLOBALS ---------------------------- */
+
+int verbosity = 0; /* no verbosity by default */
+int recverrok = 0; /* ok to proceed after socket receive errors */
+enum {NO_METH = 0, GET, HEAD, PUT, POST, CUSTOM_METHOD} method = NO_METH;
+const char *method_str[] = {"bug", "GET", "HEAD", "PUT", "POST", ""};
+int send_body = 0; /* non-zero if sending body with request */
+int requests = 1; /* Number of requests to make */
+int heartbeatres = 100; /* How often do we say we're alive */
+int concurrency = 1; /* Number of multiple requests to make */
+int percentile = 1; /* Show percentile served */
+int nolength = 0; /* Accept variable document length */
+int confidence = 1; /* Show confidence estimator and warnings */
+int tlimit = 0; /* time limit in secs */
+int keepalive = 0; /* try and do keepalive connections */
+int windowsize = 0; /* we use the OS default window size */
+char servername[1024]; /* name that server reports */
+char *hostname; /* host name from URL */
+const char *host_field; /* value of "Host:" header field */
+const char *path; /* path name */
+char *postdata; /* *buffer containing data from postfile */
+apr_size_t postlen = 0; /* length of data to be POSTed */
+char *content_type = NULL; /* content type to put in POST header */
+const char *cookie, /* optional cookie line */
+ *auth, /* optional (basic/uuencoded) auhentication */
+ *hdrs; /* optional arbitrary headers */
+apr_port_t port; /* port number */
+char *proxyhost = NULL; /* proxy host name */
+int proxyport = 0; /* proxy port */
+const char *connecthost;
+const char *myhost;
+apr_port_t connectport;
+const char *gnuplot; /* GNUplot file */
+const char *csvperc; /* CSV Percentile file */
+const char *fullurl;
+const char *colonhost;
+int isproxy = 0;
+apr_interval_time_t aprtimeout = apr_time_from_sec(30); /* timeout value */
+
+/* overrides for ab-generated common headers */
+const char *opt_host; /* which optional "Host:" header specified, if any */
+int opt_useragent = 0; /* was an optional "User-Agent:" header specified? */
+int opt_accept = 0; /* was an optional "Accept:" header specified? */
+ /*
+ * XXX - this is now a per read/write transact type of value
+ */
+
+int use_html = 0; /* use html in the report */
+const char *tablestring;
+const char *trstring;
+const char *tdstring;
+
+apr_size_t doclen = 0; /* the length the document should be */
+apr_int64_t totalread = 0; /* total number of bytes read */
+apr_int64_t totalbread = 0; /* totoal amount of entity body read */
+apr_int64_t totalposted = 0; /* total number of bytes posted, inc. headers */
+int started = 0; /* number of requests started, so no excess */
+int done = 0; /* number of requests we have done */
+int doneka = 0; /* number of keep alive connections done */
+int good = 0, bad = 0; /* number of good and bad requests */
+int epipe = 0; /* number of broken pipe writes */
+int err_length = 0; /* requests failed due to response length */
+int err_conn = 0; /* requests failed due to connection drop */
+int err_recv = 0; /* requests failed due to broken read */
+int err_except = 0; /* requests failed due to exception */
+int err_response = 0; /* requests with invalid or non-200 response */
+
+#ifdef USE_SSL
+int is_ssl;
+SSL_CTX *ssl_ctx;
+char *ssl_cipher = NULL;
+char *ssl_info = NULL;
+char *ssl_cert = NULL;
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+char *ssl_tmp_key = NULL;
+#endif
+BIO *bio_out,*bio_err;
+#ifdef HAVE_TLSEXT
+int tls_use_sni = 1; /* used by default, -I disables it */
+const char *tls_sni = NULL; /* 'opt_host' if any, 'hostname' otherwise */
+#endif
+#endif
+
+apr_time_t start, lasttime, stoptime;
+
+/* global request (and its length) */
+char _request[8192];
+char *request = _request;
+apr_size_t reqlen;
+int requests_initialized = 0;
+
+/* one global throw-away buffer to read stuff into */
+char buffer[8192];
+
+/* interesting percentiles */
+int percs[] = {50, 66, 75, 80, 90, 95, 98, 99, 100};
+
+struct connection *con; /* connection array */
+struct data *stats; /* data for each request */
+apr_pool_t *cntxt;
+
+apr_pollset_t *readbits;
+
+apr_sockaddr_t *mysa;
+apr_sockaddr_t *destsa;
+
+#ifdef NOT_ASCII
+apr_xlate_t *from_ascii, *to_ascii;
+#endif
+
+static void write_request(struct connection * c);
+static void close_connection(struct connection * c);
+
+/* --------------------------------------------------------- */
+
+/* simple little function to write an error string and exit */
+
+static void err(const char *s)
+{
+ fprintf(stderr, "%s\n", s);
+ if (done)
+ printf("Total of %d requests completed\n" , done);
+ exit(1);
+}
+
+/* simple little function to write an APR error string and exit */
+
+static void apr_err(const char *s, apr_status_t rv)
+{
+ char buf[120];
+
+ fprintf(stderr,
+ "%s: %s (%d)\n",
+ s, apr_strerror(rv, buf, sizeof buf), rv);
+ if (done)
+ printf("Total of %d requests completed\n" , done);
+ exit(rv);
+}
+
+static void *xmalloc(size_t size)
+{
+ void *ret = malloc(size);
+ if (ret == NULL) {
+ fprintf(stderr, "Could not allocate memory (%"
+ APR_SIZE_T_FMT" bytes)\n", size);
+ exit(1);
+ }
+ return ret;
+}
+
+static void *xcalloc(size_t num, size_t size)
+{
+ void *ret = calloc(num, size);
+ if (ret == NULL) {
+ fprintf(stderr, "Could not allocate memory (%"
+ APR_SIZE_T_FMT" bytes)\n", size*num);
+ exit(1);
+ }
+ return ret;
+}
+
+static char *xstrdup(const char *s)
+{
+ char *ret = strdup(s);
+ if (ret == NULL) {
+ fprintf(stderr, "Could not allocate memory (%"
+ APR_SIZE_T_FMT " bytes)\n", strlen(s));
+ exit(1);
+ }
+ return ret;
+}
+
+/*
+ * Similar to standard strstr() but we ignore case in this version.
+ * Copied from ap_strcasestr().
+ */
+static char *xstrcasestr(const char *s1, const char *s2)
+{
+ char *p1, *p2;
+ if (*s2 == '\0') {
+ /* an empty s2 */
+ return((char *)s1);
+ }
+ while(1) {
+ for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
+ if (*s1 == '\0') {
+ return(NULL);
+ }
+ /* found first character of s2, see if the rest matches */
+ p1 = (char *)s1;
+ p2 = (char *)s2;
+ for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
+ if (*p1 == '\0') {
+ /* both strings ended together */
+ return((char *)s1);
+ }
+ }
+ if (*p2 == '\0') {
+ /* second string ended, a match */
+ break;
+ }
+ /* didn't find a match here, try starting at next character in s1 */
+ s1++;
+ }
+ return((char *)s1);
+}
+
+/* pool abort function */
+static int abort_on_oom(int retcode)
+{
+ fprintf(stderr, "Could not allocate memory\n");
+ exit(1);
+ /* not reached */
+ return retcode;
+}
+
+static void set_polled_events(struct connection *c, apr_int16_t new_reqevents)
+{
+ apr_status_t rv;
+
+ if (c->pollfd.reqevents != new_reqevents) {
+ if (c->pollfd.reqevents != 0) {
+ rv = apr_pollset_remove(readbits, &c->pollfd);
+ if (rv != APR_SUCCESS) {
+ apr_err("apr_pollset_remove()", rv);
+ }
+ }
+
+ if (new_reqevents != 0) {
+ c->pollfd.reqevents = new_reqevents;
+ rv = apr_pollset_add(readbits, &c->pollfd);
+ if (rv != APR_SUCCESS) {
+ apr_err("apr_pollset_add()", rv);
+ }
+ }
+ }
+}
+
+static void set_conn_state(struct connection *c, connect_state_e new_state)
+{
+ apr_int16_t events_by_state[] = {
+ 0, /* for STATE_UNCONNECTED */
+ APR_POLLOUT, /* for STATE_CONNECTING */
+ APR_POLLIN, /* for STATE_CONNECTED; we don't poll in this state,
+ * so prepare for polling in the following state --
+ * STATE_READ
+ */
+ APR_POLLIN /* for STATE_READ */
+ };
+
+ c->state = new_state;
+
+ set_polled_events(c, events_by_state[new_state]);
+}
+
+/* --------------------------------------------------------- */
+/* write out request to a connection - assumes we can write
+ * (small) request out in one go into our new socket buffer
+ *
+ */
+#ifdef USE_SSL
+static long ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long ret)
+{
+ BIO *out;
+
+ out=(BIO *)BIO_get_callback_arg(bio);
+ if (out == NULL) return(ret);
+
+ if (cmd == (BIO_CB_READ|BIO_CB_RETURN)) {
+ BIO_printf(out,"read from %p [%p] (%d bytes => %ld (0x%lX))\n",
+ bio, argp, argi, ret, ret);
+ BIO_dump(out,(char *)argp,(int)ret);
+ return(ret);
+ }
+ else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN)) {
+ BIO_printf(out,"write to %p [%p] (%d bytes => %ld (0x%lX))\n",
+ bio, argp, argi, ret, ret);
+ BIO_dump(out,(char *)argp,(int)ret);
+ }
+ return ret;
+}
+
+static void ssl_state_cb(const SSL *s, int w, int r)
+{
+ if (w & SSL_CB_ALERT) {
+ BIO_printf(bio_err, "SSL/TLS Alert [%s] %s:%s\n",
+ (w & SSL_CB_READ ? "read" : "write"),
+ SSL_alert_type_string_long(r),
+ SSL_alert_desc_string_long(r));
+ } else if (w & SSL_CB_LOOP) {
+ BIO_printf(bio_err, "SSL/TLS State [%s] %s\n",
+ (SSL_in_connect_init((SSL*)s) ? "connect" : "-"),
+ SSL_state_string_long(s));
+ } else if (w & (SSL_CB_HANDSHAKE_START|SSL_CB_HANDSHAKE_DONE)) {
+ BIO_printf(bio_err, "SSL/TLS Handshake [%s] %s\n",
+ (w & SSL_CB_HANDSHAKE_START ? "Start" : "Done"),
+ SSL_state_string_long(s));
+ }
+}
+
+#ifndef RAND_MAX
+#define RAND_MAX INT_MAX
+#endif
+
+static int ssl_rand_choosenum(int l, int h)
+{
+ int i;
+ char buf[50];
+
+ srand((unsigned int)time(NULL));
+ apr_snprintf(buf, sizeof(buf), "%.0f",
+ (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
+ i = atoi(buf)+1;
+ if (i < l) i = l;
+ if (i > h) i = h;
+ return i;
+}
+
+static void ssl_rand_seed(void)
+{
+ int n, l;
+ time_t t;
+ pid_t pid;
+ unsigned char stackdata[256];
+
+ /*
+ * seed in the current time (usually just 4 bytes)
+ */
+ t = time(NULL);
+ l = sizeof(time_t);
+ RAND_seed((unsigned char *)&t, l);
+
+ /*
+ * seed in the current process id (usually just 4 bytes)
+ */
+ pid = getpid();
+ l = sizeof(pid_t);
+ RAND_seed((unsigned char *)&pid, l);
+
+ /*
+ * seed in some current state of the run-time stack (128 bytes)
+ */
+ n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
+ RAND_seed(stackdata+n, 128);
+}
+
+static int ssl_print_connection_info(BIO *bio, SSL *ssl)
+{
+ AB_SSL_CIPHER_CONST SSL_CIPHER *c;
+ int alg_bits,bits;
+
+ BIO_printf(bio,"Transport Protocol :%s\n", SSL_get_version(ssl));
+
+ c = SSL_get_current_cipher(ssl);
+ BIO_printf(bio,"Cipher Suite Protocol :%s\n", SSL_CIPHER_get_version(c));
+ BIO_printf(bio,"Cipher Suite Name :%s\n",SSL_CIPHER_get_name(c));
+
+ bits = SSL_CIPHER_get_bits(c,&alg_bits);
+ BIO_printf(bio,"Cipher Suite Cipher Bits:%d (%d)\n",bits,alg_bits);
+
+ return(1);
+}
+
+static void ssl_print_cert_info(BIO *bio, X509 *cert)
+{
+ X509_NAME *dn;
+ EVP_PKEY *pk;
+ char buf[1024];
+
+ BIO_printf(bio, "Certificate version: %ld\n", X509_get_version(cert)+1);
+ BIO_printf(bio,"Valid from: ");
+ ASN1_UTCTIME_print(bio, X509_get_notBefore(cert));
+ BIO_printf(bio,"\n");
+
+ BIO_printf(bio,"Valid to : ");
+ ASN1_UTCTIME_print(bio, X509_get_notAfter(cert));
+ BIO_printf(bio,"\n");
+
+ pk = X509_get_pubkey(cert);
+ BIO_printf(bio,"Public key is %d bits\n",
+ EVP_PKEY_bits(pk));
+ EVP_PKEY_free(pk);
+
+ dn = X509_get_issuer_name(cert);
+ X509_NAME_oneline(dn, buf, sizeof(buf));
+ BIO_printf(bio,"The issuer name is %s\n", buf);
+
+ dn=X509_get_subject_name(cert);
+ X509_NAME_oneline(dn, buf, sizeof(buf));
+ BIO_printf(bio,"The subject name is %s\n", buf);
+
+ /* dump the extension list too */
+ BIO_printf(bio, "Extension Count: %d\n", X509_get_ext_count(cert));
+}
+
+static void ssl_print_info(struct connection *c)
+{
+ X509_STACK_TYPE *sk;
+ X509 *cert;
+ int count;
+
+ BIO_printf(bio_err, "\n");
+ sk = SSL_get_peer_cert_chain(c->ssl);
+ if ((count = SK_NUM(sk)) > 0) {
+ int i;
+ for (i=1; i<count; i++) {
+ cert = (X509 *)SK_VALUE(sk, i);
+ ssl_print_cert_info(bio_out, cert);
+ }
+ }
+ cert = SSL_get_peer_certificate(c->ssl);
+ if (cert == NULL) {
+ BIO_printf(bio_out, "Anon DH\n");
+ } else {
+ BIO_printf(bio_out, "Peer certificate\n");
+ ssl_print_cert_info(bio_out, cert);
+ X509_free(cert);
+ }
+ ssl_print_connection_info(bio_err,c->ssl);
+ SSL_SESSION_print(bio_err, SSL_get_session(c->ssl));
+ }
+
+static void ssl_proceed_handshake(struct connection *c)
+{
+ int do_next = 1;
+
+ while (do_next) {
+ int ret, ecode;
+
+ ret = SSL_do_handshake(c->ssl);
+ ecode = SSL_get_error(c->ssl, ret);
+
+ switch (ecode) {
+ case SSL_ERROR_NONE:
+ if (verbosity >= 2)
+ ssl_print_info(c);
+ if (ssl_info == NULL) {
+ AB_SSL_CIPHER_CONST SSL_CIPHER *ci;
+ X509 *cert;
+ int sk_bits, pk_bits, swork;
+
+ ci = SSL_get_current_cipher(c->ssl);
+ sk_bits = SSL_CIPHER_get_bits(ci, &swork);
+ cert = SSL_get_peer_certificate(c->ssl);
+ if (cert)
+ pk_bits = EVP_PKEY_bits(X509_get_pubkey(cert));
+ else
+ pk_bits = 0; /* Anon DH */
+
+ ssl_info = xmalloc(128);
+ apr_snprintf(ssl_info, 128, "%s,%s,%d,%d",
+ SSL_get_version(c->ssl),
+ SSL_CIPHER_get_name(ci),
+ pk_bits, sk_bits);
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ if (ssl_tmp_key == NULL) {
+ EVP_PKEY *key;
+ if (SSL_get_server_tmp_key(c->ssl, &key)) {
+ ssl_tmp_key = xmalloc(128);
+ switch (EVP_PKEY_id(key)) {
+ case EVP_PKEY_RSA:
+ apr_snprintf(ssl_tmp_key, 128, "RSA %d bits",
+ EVP_PKEY_bits(key));
+ break;
+ case EVP_PKEY_DH:
+ apr_snprintf(ssl_tmp_key, 128, "DH %d bits",
+ EVP_PKEY_bits(key));
+ break;
+#ifndef OPENSSL_NO_EC
+ case EVP_PKEY_EC: {
+ const char *cname = NULL;
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
+ int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+ EC_KEY_free(ec);
+ cname = EC_curve_nid2nist(nid);
+ if (!cname)
+ cname = OBJ_nid2sn(nid);
+
+ apr_snprintf(ssl_tmp_key, 128, "ECDH %s %d bits",
+ cname,
+ EVP_PKEY_bits(key));
+ break;
+ }
+#endif
+ default:
+ apr_snprintf(ssl_tmp_key, 128, "%s %d bits",
+ OBJ_nid2sn(EVP_PKEY_id(key)),
+ EVP_PKEY_bits(key));
+ break;
+ }
+ EVP_PKEY_free(key);
+ }
+ }
+#endif
+ write_request(c);
+ do_next = 0;
+ break;
+ case SSL_ERROR_WANT_READ:
+ set_polled_events(c, APR_POLLIN);
+ do_next = 0;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ set_polled_events(c, APR_POLLOUT);
+ do_next = 0;
+ break;
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_SYSCALL:
+ /* Unexpected result */
+ BIO_printf(bio_err, "SSL handshake failed (%d).\n", ecode);
+ ERR_print_errors(bio_err);
+ close_connection(c);
+ do_next = 0;
+ break;
+ }
+ }
+}
+
+#endif /* USE_SSL */
+
+static void write_request(struct connection * c)
+{
+ if (started >= requests) {
+ return;
+ }
+
+ do {
+ apr_time_t tnow;
+ apr_size_t l = c->rwrite;
+ apr_status_t e = APR_SUCCESS; /* prevent gcc warning */
+
+ tnow = lasttime = apr_time_now();
+
+ /*
+ * First time round ?
+ */
+ if (c->rwrite == 0) {
+ apr_socket_timeout_set(c->aprsock, 0);
+ c->connect = tnow;
+ c->rwrote = 0;
+ c->rwrite = reqlen;
+ if (send_body)
+ c->rwrite += postlen;
+ l = c->rwrite;
+ }
+ else if (tnow > c->connect + aprtimeout) {
+ printf("Send request timed out!\n");
+ close_connection(c);
+ return;
+ }
+
+#ifdef USE_SSL
+ if (c->ssl) {
+ e = SSL_write(c->ssl, request + c->rwrote, l);
+ if (e <= 0) {
+ switch (SSL_get_error(c->ssl, e)) {
+ case SSL_ERROR_WANT_READ:
+ set_polled_events(c, APR_POLLIN);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ set_polled_events(c, APR_POLLOUT);
+ break;
+ default:
+ BIO_printf(bio_err, "SSL write failed - closing connection\n");
+ ERR_print_errors(bio_err);
+ close_connection (c);
+ break;
+ }
+ return;
+ }
+ l = e;
+ }
+ else
+#endif
+ {
+ e = apr_socket_send(c->aprsock, request + c->rwrote, &l);
+ if (e != APR_SUCCESS && !l) {
+ if (!APR_STATUS_IS_EAGAIN(e)) {
+ epipe++;
+ printf("Send request failed!\n");
+ close_connection(c);
+ }
+ else {
+ set_polled_events(c, APR_POLLOUT);
+ }
+ return;
+ }
+ }
+ totalposted += l;
+ c->rwrote += l;
+ c->rwrite -= l;
+ } while (c->rwrite);
+
+ c->endwrite = lasttime = apr_time_now();
+ started++;
+ set_conn_state(c, STATE_READ);
+}
+
+/* --------------------------------------------------------- */
+
+/* calculate and output results */
+
+static int compradre(struct data * a, struct data * b)
+{
+ if ((a->ctime) < (b->ctime))
+ return -1;
+ if ((a->ctime) > (b->ctime))
+ return +1;
+ return 0;
+}
+
+static int comprando(struct data * a, struct data * b)
+{
+ if ((a->time) < (b->time))
+ return -1;
+ if ((a->time) > (b->time))
+ return +1;
+ return 0;
+}
+
+static int compri(struct data * a, struct data * b)
+{
+ apr_interval_time_t p = a->time - a->ctime;
+ apr_interval_time_t q = b->time - b->ctime;
+ if (p < q)
+ return -1;
+ if (p > q)
+ return +1;
+ return 0;
+}
+
+static int compwait(struct data * a, struct data * b)
+{
+ if ((a->waittime) < (b->waittime))
+ return -1;
+ if ((a->waittime) > (b->waittime))
+ return 1;
+ return 0;
+}
+
+static void output_results(int sig)
+{
+ double timetaken;
+
+ if (sig) {
+ lasttime = apr_time_now(); /* record final time if interrupted */
+ }
+ timetaken = (double) (lasttime - start) / APR_USEC_PER_SEC;
+
+ printf("\n\n");
+ printf("Server Software: %s\n", servername);
+ printf("Server Hostname: %s\n", hostname);
+ printf("Server Port: %hu\n", port);
+#ifdef USE_SSL
+ if (is_ssl && ssl_info) {
+ printf("SSL/TLS Protocol: %s\n", ssl_info);
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ if (is_ssl && ssl_tmp_key) {
+ printf("Server Temp Key: %s\n", ssl_tmp_key);
+ }
+#endif
+#ifdef HAVE_TLSEXT
+ if (is_ssl && tls_sni) {
+ printf("TLS Server Name: %s\n", tls_sni);
+ }
+#endif
+#endif
+ printf("\n");
+ printf("Document Path: %s\n", path);
+ if (nolength)
+ printf("Document Length: Variable\n");
+ else
+ printf("Document Length: %" APR_SIZE_T_FMT " bytes\n", doclen);
+ printf("\n");
+ printf("Concurrency Level: %d\n", concurrency);
+ printf("Time taken for tests: %.3f seconds\n", timetaken);
+ printf("Complete requests: %d\n", done);
+ printf("Failed requests: %d\n", bad);
+ if (bad)
+ printf(" (Connect: %d, Receive: %d, Length: %d, Exceptions: %d)\n",
+ err_conn, err_recv, err_length, err_except);
+ if (epipe)
+ printf("Write errors: %d\n", epipe);
+ if (err_response)
+ printf("Non-2xx responses: %d\n", err_response);
+ if (keepalive)
+ printf("Keep-Alive requests: %d\n", doneka);
+ printf("Total transferred: %" APR_INT64_T_FMT " bytes\n", totalread);
+ if (send_body)
+ printf("Total body sent: %" APR_INT64_T_FMT "\n",
+ totalposted);
+ printf("HTML transferred: %" APR_INT64_T_FMT " bytes\n", totalbread);
+
+ /* avoid divide by zero */
+ if (timetaken && done) {
+ printf("Requests per second: %.2f [#/sec] (mean)\n",
+ (double) done / timetaken);
+ printf("Time per request: %.3f [ms] (mean)\n",
+ (double) concurrency * timetaken * 1000 / done);
+ printf("Time per request: %.3f [ms] (mean, across all concurrent requests)\n",
+ (double) timetaken * 1000 / done);
+ printf("Transfer rate: %.2f [Kbytes/sec] received\n",
+ (double) totalread / 1024 / timetaken);
+ if (send_body) {
+ printf(" %.2f kb/s sent\n",
+ (double) totalposted / 1024 / timetaken);
+ printf(" %.2f kb/s total\n",
+ (double) (totalread + totalposted) / 1024 / timetaken);
+ }
+ }
+
+ if (done > 0) {
+ /* work out connection times */
+ int i;
+ apr_time_t totalcon = 0, total = 0, totald = 0, totalwait = 0;
+ apr_time_t meancon, meantot, meand, meanwait;
+ apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX, mind = AB_MAX,
+ minwait = AB_MAX;
+ apr_interval_time_t maxcon = 0, maxtot = 0, maxd = 0, maxwait = 0;
+ apr_interval_time_t mediancon = 0, mediantot = 0, mediand = 0, medianwait = 0;
+ double sdtot = 0, sdcon = 0, sdd = 0, sdwait = 0;
+
+ for (i = 0; i < done; i++) {
+ struct data *s = &stats[i];
+ mincon = ap_min(mincon, s->ctime);
+ mintot = ap_min(mintot, s->time);
+ mind = ap_min(mind, s->time - s->ctime);
+ minwait = ap_min(minwait, s->waittime);
+
+ maxcon = ap_max(maxcon, s->ctime);
+ maxtot = ap_max(maxtot, s->time);
+ maxd = ap_max(maxd, s->time - s->ctime);
+ maxwait = ap_max(maxwait, s->waittime);
+
+ totalcon += s->ctime;
+ total += s->time;
+ totald += s->time - s->ctime;
+ totalwait += s->waittime;
+ }
+ meancon = totalcon / done;
+ meantot = total / done;
+ meand = totald / done;
+ meanwait = totalwait / done;
+
+ /* calculating the sample variance: the sum of the squared deviations, divided by n-1 */
+ for (i = 0; i < done; i++) {
+ struct data *s = &stats[i];
+ double a;
+ a = ((double)s->time - meantot);
+ sdtot += a * a;
+ a = ((double)s->ctime - meancon);
+ sdcon += a * a;
+ a = ((double)s->time - (double)s->ctime - meand);
+ sdd += a * a;
+ a = ((double)s->waittime - meanwait);
+ sdwait += a * a;
+ }
+
+ sdtot = (done > 1) ? sqrt(sdtot / (done - 1)) : 0;
+ sdcon = (done > 1) ? sqrt(sdcon / (done - 1)) : 0;
+ sdd = (done > 1) ? sqrt(sdd / (done - 1)) : 0;
+ sdwait = (done > 1) ? sqrt(sdwait / (done - 1)) : 0;
+
+ /*
+ * XXX: what is better; this hideous cast of the compradre function; or
+ * the four warnings during compile ? dirkx just does not know and
+ * hates both/
+ */
+ qsort(stats, done, sizeof(struct data),
+ (int (*) (const void *, const void *)) compradre);
+ if ((done > 1) && (done % 2))
+ mediancon = (stats[done / 2].ctime + stats[done / 2 + 1].ctime) / 2;
+ else
+ mediancon = stats[done / 2].ctime;
+
+ qsort(stats, done, sizeof(struct data),
+ (int (*) (const void *, const void *)) compri);
+ if ((done > 1) && (done % 2))
+ mediand = (stats[done / 2].time + stats[done / 2 + 1].time \
+ -stats[done / 2].ctime - stats[done / 2 + 1].ctime) / 2;
+ else
+ mediand = stats[done / 2].time - stats[done / 2].ctime;
+
+ qsort(stats, done, sizeof(struct data),
+ (int (*) (const void *, const void *)) compwait);
+ if ((done > 1) && (done % 2))
+ medianwait = (stats[done / 2].waittime + stats[done / 2 + 1].waittime) / 2;
+ else
+ medianwait = stats[done / 2].waittime;
+
+ qsort(stats, done, sizeof(struct data),
+ (int (*) (const void *, const void *)) comprando);
+ if ((done > 1) && (done % 2))
+ mediantot = (stats[done / 2].time + stats[done / 2 + 1].time) / 2;
+ else
+ mediantot = stats[done / 2].time;
+
+ printf("\nConnection Times (ms)\n");
+ /*
+ * Reduce stats from apr time to milliseconds
+ */
+ mincon = ap_round_ms(mincon);
+ mind = ap_round_ms(mind);
+ minwait = ap_round_ms(minwait);
+ mintot = ap_round_ms(mintot);
+ meancon = ap_round_ms(meancon);
+ meand = ap_round_ms(meand);
+ meanwait = ap_round_ms(meanwait);
+ meantot = ap_round_ms(meantot);
+ mediancon = ap_round_ms(mediancon);
+ mediand = ap_round_ms(mediand);
+ medianwait = ap_round_ms(medianwait);
+ mediantot = ap_round_ms(mediantot);
+ maxcon = ap_round_ms(maxcon);
+ maxd = ap_round_ms(maxd);
+ maxwait = ap_round_ms(maxwait);
+ maxtot = ap_round_ms(maxtot);
+ sdcon = ap_double_ms(sdcon);
+ sdd = ap_double_ms(sdd);
+ sdwait = ap_double_ms(sdwait);
+ sdtot = ap_double_ms(sdtot);
+
+ if (confidence) {
+#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %4" APR_TIME_T_FMT " %5.1f %6" APR_TIME_T_FMT " %7" APR_TIME_T_FMT "\n"
+ printf(" min mean[+/-sd] median max\n");
+ printf("Connect: " CONF_FMT_STRING,
+ mincon, meancon, sdcon, mediancon, maxcon);
+ printf("Processing: " CONF_FMT_STRING,
+ mind, meand, sdd, mediand, maxd);
+ printf("Waiting: " CONF_FMT_STRING,
+ minwait, meanwait, sdwait, medianwait, maxwait);
+ printf("Total: " CONF_FMT_STRING,
+ mintot, meantot, sdtot, mediantot, maxtot);
+#undef CONF_FMT_STRING
+
+#define SANE(what,mean,median,sd) \
+ { \
+ double d = (double)mean - median; \
+ if (d < 0) d = -d; \
+ if (d > 2 * sd ) \
+ printf("ERROR: The median and mean for " what " are more than twice the standard\n" \
+ " deviation apart. These results are NOT reliable.\n"); \
+ else if (d > sd ) \
+ printf("WARNING: The median and mean for " what " are not within a normal deviation\n" \
+ " These results are probably not that reliable.\n"); \
+ }
+ SANE("the initial connection time", meancon, mediancon, sdcon);
+ SANE("the processing time", meand, mediand, sdd);
+ SANE("the waiting time", meanwait, medianwait, sdwait);
+ SANE("the total time", meantot, mediantot, sdtot);
+ }
+ else {
+ printf(" min avg max\n");
+#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %5" APR_TIME_T_FMT "%5" APR_TIME_T_FMT "\n"
+ printf("Connect: " CONF_FMT_STRING, mincon, meancon, maxcon);
+ printf("Processing: " CONF_FMT_STRING, mind, meand, maxd);
+ printf("Waiting: " CONF_FMT_STRING, minwait, meanwait, maxwait);
+ printf("Total: " CONF_FMT_STRING, mintot, meantot, maxtot);
+#undef CONF_FMT_STRING
+ }
+
+
+ /* Sorted on total connect times */
+ if (percentile && (done > 1)) {
+ printf("\nPercentage of the requests served within a certain time (ms)\n");
+ for (i = 0; i < sizeof(percs) / sizeof(int); i++) {
+ if (percs[i] <= 0)
+ printf(" 0%% <0> (never)\n");
+ else if (percs[i] >= 100)
+ printf(" 100%% %5" APR_TIME_T_FMT " (longest request)\n",
+ ap_round_ms(stats[done - 1].time));
+ else
+ printf(" %d%% %5" APR_TIME_T_FMT "\n", percs[i],
+ ap_round_ms(stats[(unsigned long)done * percs[i] / 100].time));
+ }
+ }
+ if (csvperc) {
+ FILE *out = fopen(csvperc, "w");
+ if (!out) {
+ perror("Cannot open CSV output file");
+ exit(1);
+ }
+ fprintf(out, "" "Percentage served" "," "Time in ms" "\n");
+ for (i = 0; i <= 100; i++) {
+ double t;
+ if (i == 0)
+ t = ap_double_ms(stats[0].time);
+ else if (i == 100)
+ t = ap_double_ms(stats[done - 1].time);
+ else
+ t = ap_double_ms(stats[(unsigned long) (0.5 + (double)done * i / 100.0)].time);
+ fprintf(out, "%d,%.3f\n", i, t);
+ }
+ fclose(out);
+ }
+ if (gnuplot) {
+ FILE *out = fopen(gnuplot, "w");
+ char tmstring[APR_CTIME_LEN];
+ if (!out) {
+ perror("Cannot open gnuplot output file");
+ exit(1);
+ }
+ fprintf(out, "starttime\tseconds\tctime\tdtime\tttime\twait\n");
+ for (i = 0; i < done; i++) {
+ (void) apr_ctime(tmstring, stats[i].starttime);
+ fprintf(out, "%s\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT
+ "\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT
+ "\t%" APR_TIME_T_FMT "\n", tmstring,
+ apr_time_sec(stats[i].starttime),
+ ap_round_ms(stats[i].ctime),
+ ap_round_ms(stats[i].time - stats[i].ctime),
+ ap_round_ms(stats[i].time),
+ ap_round_ms(stats[i].waittime));
+ }
+ fclose(out);
+ }
+ }
+
+ if (sig) {
+ exit(1);
+ }
+}
+
+/* --------------------------------------------------------- */
+
+/* calculate and output results in HTML */
+
+static void output_html_results(void)
+{
+ double timetaken = (double) (lasttime - start) / APR_USEC_PER_SEC;
+
+ printf("\n\n<table %s>\n", tablestring);
+ printf("<tr %s><th colspan=2 %s>Server Software:</th>"
+ "<td colspan=2 %s>%s</td></tr>\n",
+ trstring, tdstring, tdstring, servername);
+ printf("<tr %s><th colspan=2 %s>Server Hostname:</th>"
+ "<td colspan=2 %s>%s</td></tr>\n",
+ trstring, tdstring, tdstring, hostname);
+ printf("<tr %s><th colspan=2 %s>Server Port:</th>"
+ "<td colspan=2 %s>%hu</td></tr>\n",
+ trstring, tdstring, tdstring, port);
+ printf("<tr %s><th colspan=2 %s>Document Path:</th>"
+ "<td colspan=2 %s>%s</td></tr>\n",
+ trstring, tdstring, tdstring, path);
+ if (nolength)
+ printf("<tr %s><th colspan=2 %s>Document Length:</th>"
+ "<td colspan=2 %s>Variable</td></tr>\n",
+ trstring, tdstring, tdstring);
+ else
+ printf("<tr %s><th colspan=2 %s>Document Length:</th>"
+ "<td colspan=2 %s>%" APR_SIZE_T_FMT " bytes</td></tr>\n",
+ trstring, tdstring, tdstring, doclen);
+ printf("<tr %s><th colspan=2 %s>Concurrency Level:</th>"
+ "<td colspan=2 %s>%d</td></tr>\n",
+ trstring, tdstring, tdstring, concurrency);
+ printf("<tr %s><th colspan=2 %s>Time taken for tests:</th>"
+ "<td colspan=2 %s>%.3f seconds</td></tr>\n",
+ trstring, tdstring, tdstring, timetaken);
+ printf("<tr %s><th colspan=2 %s>Complete requests:</th>"
+ "<td colspan=2 %s>%d</td></tr>\n",
+ trstring, tdstring, tdstring, done);
+ printf("<tr %s><th colspan=2 %s>Failed requests:</th>"
+ "<td colspan=2 %s>%d</td></tr>\n",
+ trstring, tdstring, tdstring, bad);
+ if (bad)
+ printf("<tr %s><td colspan=4 %s > (Connect: %d, Length: %d, Exceptions: %d)</td></tr>\n",
+ trstring, tdstring, err_conn, err_length, err_except);
+ if (err_response)
+ printf("<tr %s><th colspan=2 %s>Non-2xx responses:</th>"
+ "<td colspan=2 %s>%d</td></tr>\n",
+ trstring, tdstring, tdstring, err_response);
+ if (keepalive)
+ printf("<tr %s><th colspan=2 %s>Keep-Alive requests:</th>"
+ "<td colspan=2 %s>%d</td></tr>\n",
+ trstring, tdstring, tdstring, doneka);
+ printf("<tr %s><th colspan=2 %s>Total transferred:</th>"
+ "<td colspan=2 %s>%" APR_INT64_T_FMT " bytes</td></tr>\n",
+ trstring, tdstring, tdstring, totalread);
+ if (send_body)
+ printf("<tr %s><th colspan=2 %s>Total body sent:</th>"
+ "<td colspan=2 %s>%" APR_INT64_T_FMT "</td></tr>\n",
+ trstring, tdstring,
+ tdstring, totalposted);
+ printf("<tr %s><th colspan=2 %s>HTML transferred:</th>"
+ "<td colspan=2 %s>%" APR_INT64_T_FMT " bytes</td></tr>\n",
+ trstring, tdstring, tdstring, totalbread);
+
+ /* avoid divide by zero */
+ if (timetaken) {
+ printf("<tr %s><th colspan=2 %s>Requests per second:</th>"
+ "<td colspan=2 %s>%.2f</td></tr>\n",
+ trstring, tdstring, tdstring, (double) done / timetaken);
+ printf("<tr %s><th colspan=2 %s>Transfer rate:</th>"
+ "<td colspan=2 %s>%.2f kb/s received</td></tr>\n",
+ trstring, tdstring, tdstring, (double) totalread / 1024 / timetaken);
+ if (send_body) {
+ printf("<tr %s><td colspan=2 %s>&nbsp;</td>"
+ "<td colspan=2 %s>%.2f kb/s sent</td></tr>\n",
+ trstring, tdstring, tdstring,
+ (double) totalposted / 1024 / timetaken);
+ printf("<tr %s><td colspan=2 %s>&nbsp;</td>"
+ "<td colspan=2 %s>%.2f kb/s total</td></tr>\n",
+ trstring, tdstring, tdstring,
+ (double) (totalread + totalposted) / 1024 / timetaken);
+ }
+ }
+ {
+ /* work out connection times */
+ int i;
+ apr_interval_time_t totalcon = 0, total = 0;
+ apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX;
+ apr_interval_time_t maxcon = 0, maxtot = 0;
+
+ for (i = 0; i < done; i++) {
+ struct data *s = &stats[i];
+ mincon = ap_min(mincon, s->ctime);
+ mintot = ap_min(mintot, s->time);
+ maxcon = ap_max(maxcon, s->ctime);
+ maxtot = ap_max(maxtot, s->time);
+ totalcon += s->ctime;
+ total += s->time;
+ }
+ /*
+ * Reduce stats from apr time to milliseconds
+ */
+ mincon = ap_round_ms(mincon);
+ mintot = ap_round_ms(mintot);
+ maxcon = ap_round_ms(maxcon);
+ maxtot = ap_round_ms(maxtot);
+ totalcon = ap_round_ms(totalcon);
+ total = ap_round_ms(total);
+
+ if (done > 0) { /* avoid division by zero (if 0 done) */
+ printf("<tr %s><th %s colspan=4>Connection Times (ms)</th></tr>\n",
+ trstring, tdstring);
+ printf("<tr %s><th %s>&nbsp;</th> <th %s>min</th> <th %s>avg</th> <th %s>max</th></tr>\n",
+ trstring, tdstring, tdstring, tdstring, tdstring);
+ printf("<tr %s><th %s>Connect:</th>"
+ "<td %s>%5" APR_TIME_T_FMT "</td>"
+ "<td %s>%5" APR_TIME_T_FMT "</td>"
+ "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
+ trstring, tdstring, tdstring, mincon, tdstring, totalcon / done, tdstring, maxcon);
+ printf("<tr %s><th %s>Processing:</th>"
+ "<td %s>%5" APR_TIME_T_FMT "</td>"
+ "<td %s>%5" APR_TIME_T_FMT "</td>"
+ "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
+ trstring, tdstring, tdstring, mintot - mincon, tdstring,
+ (total / done) - (totalcon / done), tdstring, maxtot - maxcon);
+ printf("<tr %s><th %s>Total:</th>"
+ "<td %s>%5" APR_TIME_T_FMT "</td>"
+ "<td %s>%5" APR_TIME_T_FMT "</td>"
+ "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
+ trstring, tdstring, tdstring, mintot, tdstring, total / done, tdstring, maxtot);
+ }
+ printf("</table>\n");
+ }
+}
+
+/* --------------------------------------------------------- */
+
+/* start asnchronous non-blocking connection */
+
+static void start_connect(struct connection * c)
+{
+ apr_status_t rv;
+
+ if (!(started < requests))
+ return;
+
+ c->read = 0;
+ c->bread = 0;
+ c->keepalive = 0;
+ c->cbx = 0;
+ c->gotheader = 0;
+ c->rwrite = 0;
+ if (c->ctx)
+ apr_pool_clear(c->ctx);
+ else
+ apr_pool_create(&c->ctx, cntxt);
+
+ if ((rv = apr_socket_create(&c->aprsock, destsa->family,
+ SOCK_STREAM, 0, c->ctx)) != APR_SUCCESS) {
+ apr_err("socket", rv);
+ }
+
+ if (myhost) {
+ if ((rv = apr_socket_bind(c->aprsock, mysa)) != APR_SUCCESS) {
+ apr_err("bind", rv);
+ }
+ }
+
+ c->pollfd.desc_type = APR_POLL_SOCKET;
+ c->pollfd.desc.s = c->aprsock;
+ c->pollfd.reqevents = 0;
+ c->pollfd.client_data = c;
+
+ if ((rv = apr_socket_opt_set(c->aprsock, APR_SO_NONBLOCK, 1))
+ != APR_SUCCESS) {
+ apr_err("socket nonblock", rv);
+ }
+
+ if (windowsize != 0) {
+ rv = apr_socket_opt_set(c->aprsock, APR_SO_SNDBUF,
+ windowsize);
+ if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
+ apr_err("socket send buffer", rv);
+ }
+ rv = apr_socket_opt_set(c->aprsock, APR_SO_RCVBUF,
+ windowsize);
+ if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
+ apr_err("socket receive buffer", rv);
+ }
+ }
+
+ c->start = lasttime = apr_time_now();
+#ifdef USE_SSL
+ if (is_ssl) {
+ BIO *bio;
+ apr_os_sock_t fd;
+
+ if ((c->ssl = SSL_new(ssl_ctx)) == NULL) {
+ BIO_printf(bio_err, "SSL_new failed.\n");
+ ERR_print_errors(bio_err);
+ exit(1);
+ }
+ ssl_rand_seed();
+ apr_os_sock_get(&fd, c->aprsock);
+ bio = BIO_new_socket(fd, BIO_NOCLOSE);
+ BIO_set_nbio(bio, 1);
+ SSL_set_bio(c->ssl, bio, bio);
+ SSL_set_connect_state(c->ssl);
+ if (verbosity >= 4) {
+ BIO_set_callback(bio, ssl_print_cb);
+ BIO_set_callback_arg(bio, (void *)bio_err);
+ }
+#ifdef HAVE_TLSEXT
+ if (tls_sni) {
+ SSL_set_tlsext_host_name(c->ssl, tls_sni);
+ }
+#endif
+ } else {
+ c->ssl = NULL;
+ }
+#endif
+ if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) {
+ if (APR_STATUS_IS_EINPROGRESS(rv)) {
+ set_conn_state(c, STATE_CONNECTING);
+ c->rwrite = 0;
+ return;
+ }
+ else {
+ set_conn_state(c, STATE_UNCONNECTED);
+ apr_socket_close(c->aprsock);
+ if (good == 0 && destsa->next) {
+ destsa = destsa->next;
+ err_conn = 0;
+ }
+ else if (bad++ > 10) {
+ fprintf(stderr,
+ "\nTest aborted after 10 failures\n\n");
+ apr_err("apr_socket_connect()", rv);
+ }
+ else {
+ err_conn++;
+ }
+
+ start_connect(c);
+ return;
+ }
+ }
+
+ /* connected first time */
+ set_conn_state(c, STATE_CONNECTED);
+#ifdef USE_SSL
+ if (c->ssl) {
+ ssl_proceed_handshake(c);
+ } else
+#endif
+ {
+ write_request(c);
+ }
+}
+
+/* --------------------------------------------------------- */
+
+/* close down connection and save stats */
+
+static void close_connection(struct connection * c)
+{
+ if (c->read == 0 && c->keepalive) {
+ /*
+ * server has legitimately shut down an idle keep alive request
+ */
+ if (good)
+ good--; /* connection never happened */
+ }
+ else {
+ if (good == 1) {
+ /* first time here */
+ doclen = c->bread;
+ }
+ else if ((c->bread != doclen) && !nolength) {
+ bad++;
+ err_length++;
+ }
+ /* save out time */
+ if (done < requests) {
+ struct data *s = &stats[done++];
+ c->done = lasttime = apr_time_now();
+ s->starttime = c->start;
+ s->ctime = ap_max(0, c->connect - c->start);
+ s->time = ap_max(0, c->done - c->start);
+ s->waittime = ap_max(0, c->beginread - c->endwrite);
+ if (heartbeatres && !(done % heartbeatres)) {
+ fprintf(stderr, "Completed %d requests\n", done);
+ fflush(stderr);
+ }
+ }
+ }
+
+ set_conn_state(c, STATE_UNCONNECTED);
+#ifdef USE_SSL
+ if (c->ssl) {
+ SSL_shutdown(c->ssl);
+ SSL_free(c->ssl);
+ c->ssl = NULL;
+ }
+#endif
+ apr_socket_close(c->aprsock);
+
+ /* connect again */
+ start_connect(c);
+ return;
+}
+
+/* --------------------------------------------------------- */
+
+/* read data from connection */
+
+static void read_connection(struct connection * c)
+{
+ apr_size_t r;
+ apr_status_t status;
+ char *part;
+ char respcode[4]; /* 3 digits and null */
+ int i;
+
+ r = sizeof(buffer);
+read_more:
+#ifdef USE_SSL
+ if (c->ssl) {
+ status = SSL_read(c->ssl, buffer, r);
+ if (status <= 0) {
+ int scode = SSL_get_error(c->ssl, status);
+
+ if (scode == SSL_ERROR_ZERO_RETURN) {
+ /* connection closed cleanly: */
+ good++;
+ close_connection(c);
+ }
+ else if (scode == SSL_ERROR_SYSCALL
+ && status == 0
+ && c->read != 0) {
+ /* connection closed, but in violation of the protocol, after
+ * some data has already been read; this commonly happens, so
+ * let the length check catch any response errors
+ */
+ good++;
+ close_connection(c);
+ }
+ else if (scode == SSL_ERROR_SYSCALL
+ && c->read == 0
+ && destsa->next
+ && c->state == STATE_CONNECTING
+ && good == 0) {
+ return;
+ }
+ else if (scode == SSL_ERROR_WANT_READ) {
+ set_polled_events(c, APR_POLLIN);
+ }
+ else if (scode == SSL_ERROR_WANT_WRITE) {
+ set_polled_events(c, APR_POLLOUT);
+ }
+ else {
+ /* some fatal error: */
+ c->read = 0;
+ BIO_printf(bio_err, "SSL read failed (%d) - closing connection\n", scode);
+ ERR_print_errors(bio_err);
+ close_connection(c);
+ }
+ return;
+ }
+ r = status;
+ }
+ else
+#endif
+ {
+ status = apr_socket_recv(c->aprsock, buffer, &r);
+ if (APR_STATUS_IS_EAGAIN(status))
+ return;
+ else if (r == 0 && APR_STATUS_IS_EOF(status)) {
+ good++;
+ close_connection(c);
+ return;
+ }
+ /* catch legitimate fatal apr_socket_recv errors */
+ else if (status != APR_SUCCESS) {
+ if (recverrok) {
+ err_recv++;
+ bad++;
+ close_connection(c);
+ if (verbosity >= 1) {
+ char buf[120];
+ fprintf(stderr,"%s: %s (%d)\n", "apr_socket_recv", apr_strerror(status, buf, sizeof buf), status);
+ }
+ return;
+ } else if (destsa->next && c->state == STATE_CONNECTING
+ && c->read == 0 && good == 0) {
+ return;
+ }
+ else {
+ err_recv++;
+ apr_err("apr_socket_recv", status);
+ }
+ }
+ }
+
+ totalread += r;
+ if (c->read == 0) {
+ c->beginread = apr_time_now();
+ }
+ c->read += r;
+
+
+ if (!c->gotheader) {
+ char *s;
+ int l = 4;
+ apr_size_t space = CBUFFSIZE - c->cbx - 1; /* -1 allows for \0 term */
+ int tocopy = (space < r) ? space : r;
+#ifdef NOT_ASCII
+ apr_size_t inbytes_left = space, outbytes_left = space;
+
+ status = apr_xlate_conv_buffer(from_ascii, buffer, &inbytes_left,
+ c->cbuff + c->cbx, &outbytes_left);
+ if (status || inbytes_left || outbytes_left) {
+ fprintf(stderr, "only simple translation is supported (%d/%" APR_SIZE_T_FMT
+ "/%" APR_SIZE_T_FMT ")\n", status, inbytes_left, outbytes_left);
+ exit(1);
+ }
+#else
+ memcpy(c->cbuff + c->cbx, buffer, space);
+#endif /* NOT_ASCII */
+ c->cbx += tocopy;
+ space -= tocopy;
+ c->cbuff[c->cbx] = 0; /* terminate for benefit of strstr */
+ if (verbosity >= 2) {
+ printf("LOG: header received:\n%s\n", c->cbuff);
+ }
+ s = strstr(c->cbuff, "\r\n\r\n");
+ /*
+ * this next line is so that we talk to NCSA 1.5 which blatantly
+ * breaks the http specifaction
+ */
+ if (!s) {
+ s = strstr(c->cbuff, "\n\n");
+ l = 2;
+ }
+
+ if (!s) {
+ /* read rest next time */
+ if (space) {
+ return;
+ }
+ else {
+ /* header is in invalid or too big - close connection */
+ set_conn_state(c, STATE_UNCONNECTED);
+ apr_socket_close(c->aprsock);
+ err_response++;
+ if (bad++ > 10) {
+ err("\nTest aborted after 10 failures\n\n");
+ }
+ start_connect(c);
+ }
+ }
+ else {
+ /* have full header */
+ if (!good) {
+ /*
+ * this is first time, extract some interesting info
+ */
+ char *p, *q;
+ size_t len = 0;
+ p = xstrcasestr(c->cbuff, "Server:");
+ q = servername;
+ if (p) {
+ p += 8;
+ /* -1 to not overwrite last '\0' byte */
+ while (*p > 32 && len++ < sizeof(servername) - 1)
+ *q++ = *p++;
+ }
+ *q = 0;
+ }
+ /*
+ * XXX: this parsing isn't even remotely HTTP compliant... but in
+ * the interest of speed it doesn't totally have to be, it just
+ * needs to be extended to handle whatever servers folks want to
+ * test against. -djg
+ */
+
+ /* check response code */
+ part = strstr(c->cbuff, "HTTP"); /* really HTTP/1.x_ */
+ if (part && strlen(part) > strlen("HTTP/1.x_")) {
+ strncpy(respcode, (part + strlen("HTTP/1.x_")), 3);
+ respcode[3] = '\0';
+ }
+ else {
+ strcpy(respcode, "500");
+ }
+
+ if (respcode[0] != '2') {
+ err_response++;
+ if (verbosity >= 2)
+ printf("WARNING: Response code not 2xx (%s)\n", respcode);
+ }
+ else if (verbosity >= 3) {
+ printf("LOG: Response code = %s\n", respcode);
+ }
+ c->gotheader = 1;
+ *s = 0; /* terminate at end of header */
+ if (keepalive && xstrcasestr(c->cbuff, "Keep-Alive")) {
+ char *cl;
+ c->keepalive = 1;
+ cl = xstrcasestr(c->cbuff, "Content-Length:");
+ if (cl && method != HEAD) {
+ /* response to HEAD doesn't have entity body */
+ c->length = atoi(cl + 16);
+ }
+ else {
+ c->length = 0;
+ }
+ }
+ c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy;
+ totalbread += c->bread;
+
+ /* We have received the header, so we know this destination socket
+ * address is working, so initialize all remaining requests. */
+ if (!requests_initialized) {
+ for (i = 1; i < concurrency; i++) {
+ con[i].socknum = i;
+ start_connect(&con[i]);
+ }
+ requests_initialized = 1;
+ }
+ }
+ }
+ else {
+ /* outside header, everything we have read is entity body */
+ c->bread += r;
+ totalbread += r;
+ }
+ if (r == sizeof(buffer) && c->bread < c->length) {
+ /* read was full, try more immediately (nonblocking already) */
+ goto read_more;
+ }
+
+ if (c->keepalive && (c->bread >= c->length)) {
+ /* finished a keep-alive connection */
+ good++;
+ /* save out time */
+ if (good == 1) {
+ /* first time here */
+ doclen = c->bread;
+ }
+ else if ((c->bread != doclen) && !nolength) {
+ bad++;
+ err_length++;
+ }
+ if (done < requests) {
+ struct data *s = &stats[done++];
+ doneka++;
+ c->done = apr_time_now();
+ s->starttime = c->start;
+ s->ctime = ap_max(0, c->connect - c->start);
+ s->time = ap_max(0, c->done - c->start);
+ s->waittime = ap_max(0, c->beginread - c->endwrite);
+ if (heartbeatres && !(done % heartbeatres)) {
+ fprintf(stderr, "Completed %d requests\n", done);
+ fflush(stderr);
+ }
+ }
+ c->keepalive = 0;
+ c->length = 0;
+ c->gotheader = 0;
+ c->cbx = 0;
+ c->read = c->bread = 0;
+ /* zero connect time with keep-alive */
+ c->start = c->connect = lasttime = apr_time_now();
+ set_conn_state(c, STATE_CONNECTED);
+ write_request(c);
+ }
+}
+
+/* --------------------------------------------------------- */
+
+/* run the tests */
+
+static void test(void)
+{
+ apr_time_t stoptime;
+ apr_int16_t rtnev;
+ apr_status_t rv;
+ int i;
+ apr_status_t status;
+ int snprintf_res = 0;
+#ifdef NOT_ASCII
+ apr_size_t inbytes_left, outbytes_left;
+#endif
+
+ if (isproxy) {
+ connecthost = apr_pstrdup(cntxt, proxyhost);
+ connectport = proxyport;
+ }
+ else {
+ connecthost = apr_pstrdup(cntxt, hostname);
+ connectport = port;
+ }
+
+ if (!use_html) {
+ printf("Benchmarking %s ", hostname);
+ if (isproxy)
+ printf("[through %s:%d] ", proxyhost, proxyport);
+ printf("(be patient)%s",
+ (heartbeatres ? "\n" : "..."));
+ fflush(stdout);
+ }
+
+ con = xcalloc(concurrency, sizeof(struct connection));
+
+ /*
+ * XXX: a way to calculate the stats without requiring O(requests) memory
+ * XXX: would be nice.
+ */
+ stats = xcalloc(requests, sizeof(struct data));
+
+ if ((status = apr_pollset_create(&readbits, concurrency, cntxt,
+ APR_POLLSET_NOCOPY)) != APR_SUCCESS) {
+ apr_err("apr_pollset_create failed", status);
+ }
+
+ /* add default headers if necessary */
+ if (!opt_host) {
+ /* Host: header not overridden, add default value to hdrs */
+ hdrs = apr_pstrcat(cntxt, hdrs, "Host: ", host_field, colonhost, "\r\n", NULL);
+ }
+ else {
+ /* Header overridden, no need to add, as it is already in hdrs */
+ }
+
+#ifdef HAVE_TLSEXT
+ if (is_ssl && tls_use_sni) {
+ apr_ipsubnet_t *ip;
+ if (((tls_sni = opt_host) || (tls_sni = hostname)) &&
+ (!*tls_sni || apr_ipsubnet_create(&ip, tls_sni, NULL,
+ cntxt) == APR_SUCCESS)) {
+ /* IP not allowed in TLS SNI extension */
+ tls_sni = NULL;
+ }
+ }
+#endif
+
+ if (!opt_useragent) {
+ /* User-Agent: header not overridden, add default value to hdrs */
+ hdrs = apr_pstrcat(cntxt, hdrs, "User-Agent: ApacheBench/", AP_AB_BASEREVISION, "\r\n", NULL);
+ }
+ else {
+ /* Header overridden, no need to add, as it is already in hdrs */
+ }
+
+ if (!opt_accept) {
+ /* Accept: header not overridden, add default value to hdrs */
+ hdrs = apr_pstrcat(cntxt, hdrs, "Accept: */*\r\n", NULL);
+ }
+ else {
+ /* Header overridden, no need to add, as it is already in hdrs */
+ }
+
+ /* setup request */
+ if (!send_body) {
+ snprintf_res = apr_snprintf(request, sizeof(_request),
+ "%s %s HTTP/1.0\r\n"
+ "%s" "%s" "%s"
+ "%s" "\r\n",
+ method_str[method],
+ (isproxy) ? fullurl : path,
+ keepalive ? "Connection: Keep-Alive\r\n" : "",
+ cookie, auth, hdrs);
+ }
+ else {
+ snprintf_res = apr_snprintf(request, sizeof(_request),
+ "%s %s HTTP/1.0\r\n"
+ "%s" "%s" "%s"
+ "Content-length: %" APR_SIZE_T_FMT "\r\n"
+ "Content-type: %s\r\n"
+ "%s"
+ "\r\n",
+ method_str[method],
+ (isproxy) ? fullurl : path,
+ keepalive ? "Connection: Keep-Alive\r\n" : "",
+ cookie, auth,
+ postlen,
+ (content_type != NULL) ? content_type : "text/plain", hdrs);
+ }
+ if (snprintf_res >= sizeof(_request)) {
+ err("Request too long\n");
+ }
+
+ if (verbosity >= 2)
+ printf("INFO: %s header == \n---\n%s\n---\n",
+ method_str[method], request);
+
+ reqlen = strlen(request);
+
+ /*
+ * Combine headers and (optional) post file into one continuous buffer
+ */
+ if (send_body) {
+ char *buff = xmalloc(postlen + reqlen + 1);
+ strcpy(buff, request);
+ memcpy(buff + reqlen, postdata, postlen);
+ request = buff;
+ }
+
+#ifdef NOT_ASCII
+ inbytes_left = outbytes_left = reqlen;
+ status = apr_xlate_conv_buffer(to_ascii, request, &inbytes_left,
+ request, &outbytes_left);
+ if (status || inbytes_left || outbytes_left) {
+ fprintf(stderr, "only simple translation is supported (%d/%"
+ APR_SIZE_T_FMT "/%" APR_SIZE_T_FMT ")\n",
+ status, inbytes_left, outbytes_left);
+ exit(1);
+ }
+#endif /* NOT_ASCII */
+
+ if (myhost) {
+ /* This only needs to be done once */
+ if ((rv = apr_sockaddr_info_get(&mysa, myhost, APR_UNSPEC, 0, 0, cntxt)) != APR_SUCCESS) {
+ char buf[120];
+ apr_snprintf(buf, sizeof(buf),
+ "apr_sockaddr_info_get() for %s", myhost);
+ apr_err(buf, rv);
+ }
+ }
+
+ /* This too */
+ if ((rv = apr_sockaddr_info_get(&destsa, connecthost,
+ myhost ? mysa->family : APR_UNSPEC,
+ connectport, 0, cntxt))
+ != APR_SUCCESS) {
+ char buf[120];
+ apr_snprintf(buf, sizeof(buf),
+ "apr_sockaddr_info_get() for %s", connecthost);
+ apr_err(buf, rv);
+ }
+
+ /* ok - lets start */
+ start = lasttime = apr_time_now();
+ stoptime = tlimit ? (start + apr_time_from_sec(tlimit)) : AB_MAX;
+
+#ifdef SIGINT
+ /* Output the results if the user terminates the run early. */
+ apr_signal(SIGINT, output_results);
+#endif
+
+ /* initialise first connection to determine destination socket address
+ * which should be used for next connections. */
+ con[0].socknum = 0;
+ start_connect(&con[0]);
+
+ do {
+ apr_int32_t n;
+ const apr_pollfd_t *pollresults, *pollfd;
+
+ n = concurrency;
+ do {
+ status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
+ } while (APR_STATUS_IS_EINTR(status));
+ if (status != APR_SUCCESS)
+ apr_err("apr_pollset_poll", status);
+
+ for (i = 0, pollfd = pollresults; i < n; i++, pollfd++) {
+ struct connection *c;
+
+ c = pollfd->client_data;
+
+ /*
+ * If the connection isn't connected how can we check it?
+ */
+ if (c->state == STATE_UNCONNECTED)
+ continue;
+
+ rtnev = pollfd->rtnevents;
+
+#ifdef USE_SSL
+ if (c->state == STATE_CONNECTED && c->ssl && SSL_in_init(c->ssl)) {
+ ssl_proceed_handshake(c);
+ continue;
+ }
+#endif
+
+ /*
+ * Notes: APR_POLLHUP is set after FIN is received on some
+ * systems, so treat that like APR_POLLIN so that we try to read
+ * again.
+ *
+ * Some systems return APR_POLLERR with APR_POLLHUP. We need to
+ * call read_connection() for APR_POLLHUP, so check for
+ * APR_POLLHUP first so that a closed connection isn't treated
+ * like an I/O error. If it is, we never figure out that the
+ * connection is done and we loop here endlessly calling
+ * apr_poll().
+ */
+ if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP))
+ read_connection(c);
+ if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) {
+ if (destsa->next && c->state == STATE_CONNECTING && good == 0) {
+ destsa = destsa->next;
+ start_connect(c);
+ }
+ else {
+ bad++;
+ err_except++;
+ /* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */
+ if (c->state == STATE_CONNECTING) {
+ read_connection(c);
+ }
+ else {
+ start_connect(c);
+ }
+ }
+ continue;
+ }
+ if (rtnev & APR_POLLOUT) {
+ if (c->state == STATE_CONNECTING) {
+ /* call connect() again to detect errors */
+ rv = apr_socket_connect(c->aprsock, destsa);
+ if (rv != APR_SUCCESS) {
+ set_conn_state(c, STATE_UNCONNECTED);
+ apr_socket_close(c->aprsock);
+ err_conn++;
+ if (bad++ > 10) {
+ fprintf(stderr,
+ "\nTest aborted after 10 failures\n\n");
+ apr_err("apr_socket_connect()", rv);
+ }
+ start_connect(c);
+ continue;
+ }
+ else {
+ set_conn_state(c, STATE_CONNECTED);
+#ifdef USE_SSL
+ if (c->ssl)
+ ssl_proceed_handshake(c);
+ else
+#endif
+ write_request(c);
+ }
+ }
+ else {
+ /* POLLOUT is one shot */
+ set_polled_events(c, APR_POLLIN);
+ if (c->state == STATE_READ) {
+ read_connection(c);
+ }
+ else {
+ write_request(c);
+ }
+ }
+ }
+ }
+ } while (lasttime < stoptime && done < requests);
+
+ if (heartbeatres)
+ fprintf(stderr, "Finished %d requests\n", done);
+ else
+ printf("..done\n");
+
+ if (use_html)
+ output_html_results();
+ else
+ output_results(0);
+}
+
+/* ------------------------------------------------------- */
+
+/* display copyright information */
+static void copyright(void)
+{
+ if (!use_html) {
+ printf("This is ApacheBench, Version %s\n", AP_AB_BASEREVISION " <$Revision: 1903618 $>");
+ printf("Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\n");
+ printf("Licensed to The Apache Software Foundation, http://www.apache.org/\n");
+ printf("\n");
+ }
+ else {
+ printf("<p>\n");
+ printf(" This is ApacheBench, Version %s <i>&lt;%s&gt;</i><br>\n", AP_AB_BASEREVISION, "$Revision: 1903618 $");
+ printf(" Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/<br>\n");
+ printf(" Licensed to The Apache Software Foundation, http://www.apache.org/<br>\n");
+ printf("</p>\n<p>\n");
+ }
+}
+
+/* display usage information */
+static void usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [options] [http"
+#ifdef USE_SSL
+ "[s]"
+#endif
+ "://]hostname[:port]/path\n", progname);
+/* 80 column ruler: ********************************************************************************
+ */
+ fprintf(stderr, "Options are:\n");
+ fprintf(stderr, " -n requests Number of requests to perform\n");
+ fprintf(stderr, " -c concurrency Number of multiple requests to make at a time\n");
+ fprintf(stderr, " -t timelimit Seconds to max. to spend on benchmarking\n");
+ fprintf(stderr, " This implies -n 50000\n");
+ fprintf(stderr, " -s timeout Seconds to max. wait for each response\n");
+ fprintf(stderr, " Default is 30 seconds\n");
+ fprintf(stderr, " -b windowsize Size of TCP send/receive buffer, in bytes\n");
+ fprintf(stderr, " -B address Address to bind to when making outgoing connections\n");
+ fprintf(stderr, " -p postfile File containing data to POST. Remember also to set -T\n");
+ fprintf(stderr, " -u putfile File containing data to PUT. Remember also to set -T\n");
+ fprintf(stderr, " -T content-type Content-type header to use for POST/PUT data, eg.\n");
+ fprintf(stderr, " 'application/x-www-form-urlencoded'\n");
+ fprintf(stderr, " Default is 'text/plain'\n");
+ fprintf(stderr, " -v verbosity How much troubleshooting info to print\n");
+ fprintf(stderr, " -w Print out results in HTML tables\n");
+ fprintf(stderr, " -i Use HEAD instead of GET\n");
+ fprintf(stderr, " -x attributes String to insert as table attributes\n");
+ fprintf(stderr, " -y attributes String to insert as tr attributes\n");
+ fprintf(stderr, " -z attributes String to insert as td or th attributes\n");
+ fprintf(stderr, " -C attribute Add cookie, eg. 'Apache=1234'. (repeatable)\n");
+ fprintf(stderr, " -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'\n");
+ fprintf(stderr, " Inserted after all normal header lines. (repeatable)\n");
+ fprintf(stderr, " -A attribute Add Basic WWW Authentication, the attributes\n");
+ fprintf(stderr, " are a colon separated username and password.\n");
+ fprintf(stderr, " -P attribute Add Basic Proxy Authentication, the attributes\n");
+ fprintf(stderr, " are a colon separated username and password.\n");
+ fprintf(stderr, " -X proxy:port Proxyserver and port number to use\n");
+ fprintf(stderr, " -V Print version number and exit\n");
+ fprintf(stderr, " -k Use HTTP KeepAlive feature\n");
+ fprintf(stderr, " -d Do not show percentiles served table.\n");
+ fprintf(stderr, " -S Do not show confidence estimators and warnings.\n");
+ fprintf(stderr, " -q Do not show progress when doing more than 150 requests\n");
+ fprintf(stderr, " -l Accept variable document length (use this for dynamic pages)\n");
+ fprintf(stderr, " -g filename Output collected data to gnuplot format file.\n");
+ fprintf(stderr, " -e filename Output CSV file with percentages served\n");
+ fprintf(stderr, " -r Don't exit on socket receive errors.\n");
+ fprintf(stderr, " -m method Method name\n");
+ fprintf(stderr, " -h Display usage information (this message)\n");
+#ifdef USE_SSL
+
+#ifndef OPENSSL_NO_SSL2
+#define SSL2_HELP_MSG "SSL2, "
+#else
+#define SSL2_HELP_MSG ""
+#endif
+
+#ifndef OPENSSL_NO_SSL3
+#define SSL3_HELP_MSG "SSL3, "
+#else
+#define SSL3_HELP_MSG ""
+#endif
+
+#ifdef HAVE_TLSV1_X
+
+#ifdef TLS1_3_VERSION
+#define TLS1_X_HELP_MSG ", TLS1.1, TLS1.2, TLS1.3"
+#else
+#define TLS1_X_HELP_MSG ", TLS1.1, TLS1.2"
+#endif
+
+#else
+#define TLS1_X_HELP_MSG ""
+#endif
+
+#ifdef HAVE_TLSEXT
+ fprintf(stderr, " -I Disable TLS Server Name Indication (SNI) extension\n");
+#endif
+ fprintf(stderr, " -Z ciphersuite Specify SSL/TLS cipher suite (See openssl ciphers)\n");
+ fprintf(stderr, " -f protocol Specify SSL/TLS protocol\n");
+ fprintf(stderr, " (" SSL2_HELP_MSG SSL3_HELP_MSG "TLS1" TLS1_X_HELP_MSG " or ALL)\n");
+ fprintf(stderr, " -E certfile Specify optional client certificate chain and private key\n");
+#endif
+ exit(EINVAL);
+}
+
+/* ------------------------------------------------------- */
+
+/* split URL into parts */
+
+static int parse_url(const char *url)
+{
+ char *cp;
+ char *h;
+ char *scope_id;
+ apr_status_t rv;
+
+ /* Save a copy for the proxy */
+ fullurl = apr_pstrdup(cntxt, url);
+
+ if (strlen(url) > 7 && strncmp(url, "http://", 7) == 0) {
+ url += 7;
+#ifdef USE_SSL
+ is_ssl = 0;
+#endif
+ }
+ else
+#ifdef USE_SSL
+ if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
+ url += 8;
+ is_ssl = 1;
+ }
+#else
+ if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
+ fprintf(stderr, "SSL not compiled in; no https support\n");
+ exit(1);
+ }
+#endif
+
+ if ((cp = strchr(url, '/')) == NULL)
+ return 1;
+ h = apr_pstrmemdup(cntxt, url, cp - url);
+ rv = apr_parse_addr_port(&hostname, &scope_id, &port, h, cntxt);
+ if (rv != APR_SUCCESS || !hostname || scope_id) {
+ return 1;
+ }
+ path = apr_pstrdup(cntxt, cp);
+ *cp = '\0';
+ if (*url == '[') { /* IPv6 numeric address string */
+ host_field = apr_psprintf(cntxt, "[%s]", hostname);
+ }
+ else {
+ host_field = hostname;
+ }
+
+ if (port == 0) { /* no port specified */
+#ifdef USE_SSL
+ if (is_ssl)
+ port = 443;
+ else
+#endif
+ port = 80;
+ }
+
+ if ((
+#ifdef USE_SSL
+ is_ssl && (port != 443)) || (!is_ssl &&
+#endif
+ (port != 80)))
+ {
+ colonhost = apr_psprintf(cntxt,":%d",port);
+ } else
+ colonhost = "";
+ return 0;
+}
+
+/* ------------------------------------------------------- */
+
+/* read data to POST/PUT from file, save contents and length */
+
+static apr_status_t open_postfile(const char *pfile)
+{
+ apr_file_t *postfd;
+ apr_finfo_t finfo;
+ apr_status_t rv;
+ char errmsg[120];
+
+ rv = apr_file_open(&postfd, pfile, APR_READ, APR_OS_DEFAULT, cntxt);
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "ab: Could not open POST data file (%s): %s\n", pfile,
+ apr_strerror(rv, errmsg, sizeof errmsg));
+ return rv;
+ }
+
+ rv = apr_file_info_get(&finfo, APR_FINFO_NORM, postfd);
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "ab: Could not stat POST data file (%s): %s\n", pfile,
+ apr_strerror(rv, errmsg, sizeof errmsg));
+ return rv;
+ }
+ postlen = (apr_size_t)finfo.size;
+ postdata = xmalloc(postlen);
+ rv = apr_file_read_full(postfd, postdata, postlen, NULL);
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "ab: Could not read POST data file: %s\n",
+ apr_strerror(rv, errmsg, sizeof errmsg));
+ return rv;
+ }
+ apr_file_close(postfd);
+ return APR_SUCCESS;
+}
+
+/* ------------------------------------------------------- */
+
+/* sort out command-line args and call test */
+int main(int argc, const char * const argv[])
+{
+ char tmp[1024];
+ apr_status_t status;
+ apr_getopt_t *opt;
+ const char *opt_arg;
+ char c;
+#ifdef USE_SSL
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ int max_prot = MAX_SSL_PROTO;
+ int min_prot = MIN_SSL_PROTO;
+#endif /* #if OPENSSL_VERSION_NUMBER >= 0x10100000L */
+ AB_SSL_METHOD_CONST SSL_METHOD *meth = SSLv23_client_method();
+#endif /* USE_SSL */
+
+ /* table defaults */
+ tablestring = "";
+ trstring = "";
+ tdstring = "bgcolor=white";
+ cookie = "";
+ auth = "";
+ proxyhost = "";
+ hdrs = "";
+
+ apr_app_initialize(&argc, &argv, NULL);
+ atexit(apr_terminate);
+ apr_pool_create(&cntxt, NULL);
+ apr_pool_abort_set(abort_on_oom, cntxt);
+
+#ifdef NOT_ASCII
+ status = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, cntxt);
+ if (status) {
+ fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", status);
+ exit(1);
+ }
+ status = apr_xlate_open(&from_ascii, APR_DEFAULT_CHARSET, "ISO-8859-1", cntxt);
+ if (status) {
+ fprintf(stderr, "apr_xlate_open(from ASCII)->%d\n", status);
+ exit(1);
+ }
+ status = apr_base64init_ebcdic(to_ascii, from_ascii);
+ if (status) {
+ fprintf(stderr, "apr_base64init_ebcdic()->%d\n", status);
+ exit(1);
+ }
+#endif
+
+ myhost = NULL; /* 0.0.0.0 or :: */
+
+ apr_getopt_init(&opt, cntxt, argc, argv);
+ while ((status = apr_getopt(opt, "n:c:t:s:b:T:p:u:v:lrkVhwiIx:y:z:C:H:P:A:g:X:de:SqB:m:"
+#ifdef USE_SSL
+ "Z:f:E:"
+#endif
+ ,&c, &opt_arg)) == APR_SUCCESS) {
+ switch (c) {
+ case 'n':
+ requests = atoi(opt_arg);
+ if (requests <= 0) {
+ err("Invalid number of requests\n");
+ }
+ break;
+ case 'k':
+ keepalive = 1;
+ break;
+ case 'q':
+ heartbeatres = 0;
+ break;
+ case 'c':
+ concurrency = atoi(opt_arg);
+ break;
+ case 'b':
+ windowsize = atoi(opt_arg);
+ break;
+ case 'i':
+ if (method != NO_METH)
+ err("Cannot mix HEAD with other methods\n");
+ method = HEAD;
+ break;
+ case 'g':
+ gnuplot = xstrdup(opt_arg);
+ break;
+ case 'd':
+ percentile = 0;
+ break;
+ case 'e':
+ csvperc = xstrdup(opt_arg);
+ break;
+ case 'S':
+ confidence = 0;
+ break;
+ case 's':
+ aprtimeout = apr_time_from_sec(atoi(opt_arg)); /* timeout value */
+ break;
+ case 'p':
+ if (method != NO_METH)
+ err("Cannot mix POST with other methods\n");
+ if (open_postfile(opt_arg) != APR_SUCCESS) {
+ exit(1);
+ }
+ method = POST;
+ send_body = 1;
+ break;
+ case 'u':
+ if (method != NO_METH)
+ err("Cannot mix PUT with other methods\n");
+ if (open_postfile(opt_arg) != APR_SUCCESS) {
+ exit(1);
+ }
+ method = PUT;
+ send_body = 1;
+ break;
+ case 'l':
+ nolength = 1;
+ break;
+ case 'r':
+ recverrok = 1;
+ break;
+ case 'v':
+ verbosity = atoi(opt_arg);
+ break;
+ case 't':
+ tlimit = atoi(opt_arg);
+ requests = MAX_REQUESTS; /* need to size data array on
+ * something */
+ break;
+ case 'T':
+ content_type = apr_pstrdup(cntxt, opt_arg);
+ break;
+ case 'C':
+ cookie = apr_pstrcat(cntxt, "Cookie: ", opt_arg, "\r\n", NULL);
+ break;
+ case 'A':
+ /*
+ * assume username passwd already to be in colon separated form.
+ * Ready to be uu-encoded.
+ */
+ while (apr_isspace(*opt_arg))
+ opt_arg++;
+ if (apr_base64_encode_len(strlen(opt_arg)) > sizeof(tmp)) {
+ err("Authentication credentials too long\n");
+ }
+ apr_base64_encode(tmp, opt_arg, strlen(opt_arg));
+
+ auth = apr_pstrcat(cntxt, auth, "Authorization: Basic ", tmp,
+ "\r\n", NULL);
+ break;
+ case 'P':
+ /*
+ * assume username passwd already to be in colon separated form.
+ */
+ while (apr_isspace(*opt_arg))
+ opt_arg++;
+ if (apr_base64_encode_len(strlen(opt_arg)) > sizeof(tmp)) {
+ err("Proxy credentials too long\n");
+ }
+ apr_base64_encode(tmp, opt_arg, strlen(opt_arg));
+
+ auth = apr_pstrcat(cntxt, auth, "Proxy-Authorization: Basic ",
+ tmp, "\r\n", NULL);
+ break;
+ case 'H':
+ hdrs = apr_pstrcat(cntxt, hdrs, opt_arg, "\r\n", NULL);
+ /*
+ * allow override of some of the common headers that ab adds
+ */
+ if (strncasecmp(opt_arg, "Host:", 5) == 0) {
+ char *host;
+ apr_size_t len;
+ opt_arg += 5;
+ while (apr_isspace(*opt_arg))
+ opt_arg++;
+ len = strlen(opt_arg);
+ host = strdup(opt_arg);
+ while (len && apr_isspace(host[len-1]))
+ host[--len] = '\0';
+ opt_host = host;
+ } else if (strncasecmp(opt_arg, "Accept:", 7) == 0) {
+ opt_accept = 1;
+ } else if (strncasecmp(opt_arg, "User-Agent:", 11) == 0) {
+ opt_useragent = 1;
+ }
+ break;
+ case 'w':
+ use_html = 1;
+ break;
+ /*
+ * if any of the following three are used, turn on html output
+ * automatically
+ */
+ case 'x':
+ use_html = 1;
+ tablestring = opt_arg;
+ break;
+ case 'X':
+ {
+ char *p;
+ /*
+ * assume proxy-name[:port]
+ */
+ if ((p = strchr(opt_arg, ':'))) {
+ *p = '\0';
+ p++;
+ proxyport = atoi(p);
+ }
+ proxyhost = apr_pstrdup(cntxt, opt_arg);
+ isproxy = 1;
+ }
+ break;
+ case 'y':
+ use_html = 1;
+ trstring = opt_arg;
+ break;
+ case 'z':
+ use_html = 1;
+ tdstring = opt_arg;
+ break;
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'V':
+ copyright();
+ return 0;
+ case 'B':
+ myhost = apr_pstrdup(cntxt, opt_arg);
+ break;
+ case 'm':
+ method = CUSTOM_METHOD;
+ method_str[CUSTOM_METHOD] = strdup(opt_arg);
+ break;
+#ifdef USE_SSL
+ case 'Z':
+ ssl_cipher = strdup(opt_arg);
+ break;
+ case 'E':
+ ssl_cert = strdup(opt_arg);
+ break;
+ case 'f':
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ if (strncasecmp(opt_arg, "ALL", 3) == 0) {
+ meth = SSLv23_client_method();
+#ifndef OPENSSL_NO_SSL2
+ } else if (strncasecmp(opt_arg, "SSL2", 4) == 0) {
+ meth = SSLv2_client_method();
+#ifdef HAVE_TLSEXT
+ tls_use_sni = 0;
+#endif
+#endif
+#ifndef OPENSSL_NO_SSL3
+ } else if (strncasecmp(opt_arg, "SSL3", 4) == 0) {
+ meth = SSLv3_client_method();
+#ifdef HAVE_TLSEXT
+ tls_use_sni = 0;
+#endif
+#endif
+#ifdef HAVE_TLSV1_X
+ } else if (strncasecmp(opt_arg, "TLS1.1", 6) == 0) {
+ meth = TLSv1_1_client_method();
+ } else if (strncasecmp(opt_arg, "TLS1.2", 6) == 0) {
+ meth = TLSv1_2_client_method();
+#endif
+ } else if (strncasecmp(opt_arg, "TLS1", 4) == 0) {
+ meth = TLSv1_client_method();
+ }
+#else /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */
+ meth = TLS_client_method();
+ if (strncasecmp(opt_arg, "ALL", 3) == 0) {
+ max_prot = MAX_SSL_PROTO;
+ min_prot = MIN_SSL_PROTO;
+#ifndef OPENSSL_NO_SSL3
+ } else if (strncasecmp(opt_arg, "SSL3", 4) == 0) {
+ max_prot = SSL3_VERSION;
+ min_prot = SSL3_VERSION;
+#endif
+ } else if (strncasecmp(opt_arg, "TLS1.1", 6) == 0) {
+ max_prot = TLS1_1_VERSION;
+ min_prot = TLS1_1_VERSION;
+ } else if (strncasecmp(opt_arg, "TLS1.2", 6) == 0) {
+ max_prot = TLS1_2_VERSION;
+ min_prot = TLS1_2_VERSION;
+#ifdef TLS1_3_VERSION
+ } else if (strncasecmp(opt_arg, "TLS1.3", 6) == 0) {
+ max_prot = TLS1_3_VERSION;
+ min_prot = TLS1_3_VERSION;
+#endif
+ } else if (strncasecmp(opt_arg, "TLS1", 4) == 0) {
+ max_prot = TLS1_VERSION;
+ min_prot = TLS1_VERSION;
+ }
+#endif /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */
+ break;
+#ifdef HAVE_TLSEXT
+ case 'I':
+ tls_use_sni = 0;
+ break;
+#endif
+#endif /* USE_SSL */
+ }
+ }
+
+ if (opt->ind != argc - 1) {
+ fprintf(stderr, "%s: wrong number of arguments\n", argv[0]);
+ usage(argv[0]);
+ }
+
+ if (method == NO_METH) {
+ method = GET;
+ }
+
+ if (parse_url(apr_pstrdup(cntxt, opt->argv[opt->ind++]))) {
+ fprintf(stderr, "%s: invalid URL\n", argv[0]);
+ usage(argv[0]);
+ }
+
+ if ((concurrency < 0) || (concurrency > MAX_CONCURRENCY)) {
+ fprintf(stderr, "%s: Invalid Concurrency [Range 0..%d]\n",
+ argv[0], MAX_CONCURRENCY);
+ usage(argv[0]);
+ }
+
+ if (concurrency > requests) {
+ fprintf(stderr, "%s: Cannot use concurrency level greater than "
+ "total number of requests\n", argv[0]);
+ usage(argv[0]);
+ }
+
+ if ((heartbeatres) && (requests > 150)) {
+ heartbeatres = requests / 10; /* Print line every 10% of requests */
+ if (heartbeatres < 100)
+ heartbeatres = 100; /* but never more often than once every 100
+ * connections. */
+ }
+ else
+ heartbeatres = 0;
+
+#ifdef USE_SSL
+#ifdef RSAREF
+ R_malloc_init();
+#else
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ CRYPTO_malloc_init();
+#endif
+#endif
+ SSL_load_error_strings();
+ SSL_library_init();
+ bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
+ bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
+
+ if (!(ssl_ctx = SSL_CTX_new(meth))) {
+ BIO_printf(bio_err, "Could not initialize SSL Context.\n");
+ ERR_print_errors(bio_err);
+ exit(1);
+ }
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ SSL_CTX_set_max_proto_version(ssl_ctx, max_prot);
+ SSL_CTX_set_min_proto_version(ssl_ctx, min_prot);
+#endif
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ /* Keep memory usage as low as possible */
+ SSL_CTX_set_mode (ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+
+ if (ssl_cipher != NULL) {
+ int ok;
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && defined(TLS1_3_VERSION)
+ if (min_prot >= TLS1_3_VERSION)
+ ok = SSL_CTX_set_ciphersuites(ssl_ctx, ssl_cipher);
+ else
+#endif
+ ok = SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher);
+ if (!ok) {
+ BIO_printf(bio_err, "error setting ciphersuite list [%s]\n",
+ ssl_cipher);
+ ERR_print_errors(bio_err);
+ exit(1);
+ }
+ }
+
+ if (verbosity >= 3) {
+ SSL_CTX_set_info_callback(ssl_ctx, ssl_state_cb);
+ }
+ if (ssl_cert != NULL) {
+ if (SSL_CTX_use_certificate_chain_file(ssl_ctx, ssl_cert) <= 0) {
+ BIO_printf(bio_err, "unable to get certificate from '%s'\n",
+ ssl_cert);
+ ERR_print_errors(bio_err);
+ exit(1);
+ }
+ if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_cert, SSL_FILETYPE_PEM) <= 0) {
+ BIO_printf(bio_err, "unable to get private key from '%s'\n",
+ ssl_cert);
+ ERR_print_errors(bio_err);
+ exit(1);
+ }
+ if (!SSL_CTX_check_private_key(ssl_ctx)) {
+ BIO_printf(bio_err,
+ "private key does not match the certificate public key in %s\n", ssl_cert);
+ exit(1);
+ }
+ }
+
+#endif
+#ifdef SIGPIPE
+ apr_signal(SIGPIPE, SIG_IGN); /* Ignore writes to connections that
+ * have been closed at the other end. */
+#endif
+ copyright();
+ test();
+ apr_pool_destroy(cntxt);
+
+ return 0;
+}
diff --git a/support/ab.dep b/support/ab.dep
new file mode 100644
index 0000000..36eab1d
--- /dev/null
+++ b/support/ab.dep
@@ -0,0 +1,37 @@
+# Microsoft Developer Studio Generated Dependency File, included by ab.mak
+
+.\ab.c : \
+ "..\include\ap_release.h"\
+ "..\srclib\apr-util\include\apr_base64.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_dso.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_global_mutex.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_network_io.h"\
+ "..\srclib\apr\include\apr_poll.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_portable.h"\
+ "..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\srclib\apr\include\apr_shm.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_thread_proc.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
diff --git a/support/ab.dsp b/support/ab.dsp
new file mode 100644
index 0000000..7de1c86
--- /dev/null
+++ b/support/ab.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="ab" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=ab - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ab.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ab.mak" CFG="ab - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ab - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ab - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ab - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/ab_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\ab.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "ab - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/ab_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\ab.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "ab - Win32 Release"
+# Name "ab - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\ab.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/ab.mak b/support/ab.mak
new file mode 100644
index 0000000..669ac79
--- /dev/null
+++ b/support/ab.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on ab.dsp
+!IF "$(CFG)" == ""
+CFG=ab - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to ab - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "ab - Win32 Release" && "$(CFG)" != "ab - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ab.mak" CFG="ab - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ab - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "ab - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "ab - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\ab.obj"
+ -@erase "$(INTDIR)\ab.res"
+ -@erase "$(INTDIR)\ab_src.idb"
+ -@erase "$(INTDIR)\ab_src.pdb"
+ -@erase "$(OUTDIR)\ab.exe"
+ -@erase "$(OUTDIR)\ab.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ab_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ab.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\ab.pdb" /debug /out:"$(OUTDIR)\ab.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\ab.obj" \
+ "$(INTDIR)\ab.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\ab.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\ab.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ab.exe"
+ if exist .\Release\ab.exe.manifest mt.exe -manifest .\Release\ab.exe.manifest -outputresource:.\Release\ab.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "ab - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\ab.obj"
+ -@erase "$(INTDIR)\ab.res"
+ -@erase "$(INTDIR)\ab_src.idb"
+ -@erase "$(INTDIR)\ab_src.pdb"
+ -@erase "$(OUTDIR)\ab.exe"
+ -@erase "$(OUTDIR)\ab.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ab_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ab.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\ab.pdb" /debug /out:"$(OUTDIR)\ab.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\ab.obj" \
+ "$(INTDIR)\ab.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\ab.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\ab.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ab.exe"
+ if exist .\Debug\ab.exe.manifest mt.exe -manifest .\Debug\ab.exe.manifest -outputresource:.\Debug\ab.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("ab.dep")
+!INCLUDE "ab.dep"
+!ELSE
+!MESSAGE Warning: cannot find "ab.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "ab - Win32 Release" || "$(CFG)" == "ab - Win32 Debug"
+
+!IF "$(CFG)" == "ab - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "ab - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "ab - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "ab - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\ab.c
+
+"$(INTDIR)\ab.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "ab - Win32 Release"
+
+
+"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "ab - Win32 Debug"
+
+
+"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" $(SOURCE)
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/support/abs.dep b/support/abs.dep
new file mode 100644
index 0000000..4b6f12f
--- /dev/null
+++ b/support/abs.dep
@@ -0,0 +1,37 @@
+# Microsoft Developer Studio Generated Dependency File, included by abs.mak
+
+.\ab.c : \
+ "..\include\ap_release.h"\
+ "..\srclib\apr-util\include\apr_base64.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_dso.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_global_mutex.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_network_io.h"\
+ "..\srclib\apr\include\apr_poll.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_portable.h"\
+ "..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\srclib\apr\include\apr_shm.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_thread_proc.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
diff --git a/support/abs.dsp b/support/abs.dsp
new file mode 100644
index 0000000..bb407eb
--- /dev/null
+++ b/support/abs.dsp
@@ -0,0 +1,144 @@
+# Microsoft Developer Studio Project File - Name="abs" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=abs - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "abs.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "abs.mak" CFG="abs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "abs - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "abs - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "SSL" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /I "../srclib/openssl/inc32" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fd"Release/abs_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /libpath:"../srclib/openssl/out32dll"
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /debug /libpath:"../srclib/openssl/out32dll" /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\abs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "SSL" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /I "../srclib/openssl/inc32" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fd"Debug/abs_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /incremental:no /debug /libpath:"../srclib/openssl/out32dll"
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /incremental:no /debug /libpath:"../srclib/openssl/out32dll"
+# Begin Special Build Tool
+TargetPath=.\Debug\abs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "abs - Win32 Release"
+# Name "abs - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\ab.c
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+# ADD CPP /Fo"Release/abs.obj"
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+# ADD CPP /Fo"Debug/abs.obj"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=../include\ap_release.h
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+# Begin Custom Build - Create applink.c from ms/applink.c
+InputPath=../include\ap_release.h
+
+"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+# Begin Custom Build - Create applink.c from ms/applink.c
+InputPath=../include\ap_release.h
+
+"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/abs.mak b/support/abs.mak
new file mode 100644
index 0000000..81da635
--- /dev/null
+++ b/support/abs.mak
@@ -0,0 +1,374 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on abs.dsp
+!IF "$(CFG)" == ""
+CFG=abs - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to abs - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "abs - Win32 Release" && "$(CFG)" != "abs - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "abs.mak" CFG="abs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "abs - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "abs - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(_HAVE_OSSL110)" == "1"
+SSLCRP=libcrypto
+SSLLIB=libssl
+SSLINC=/I ../srclib/openssl/include
+SSLBIN=/libpath:../srclib/openssl
+!ELSE
+SSLCRP=libeay32
+SSLLIB=ssleay32
+SSLINC=/I ../srclib/openssl/inc32
+SSLBIN=/libpath:../srclib/openssl/out32dll
+!ENDIF
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\ab.res"
+ -@erase "$(INTDIR)\abs.obj"
+ -@erase "$(INTDIR)\abs_src.idb"
+ -@erase "$(INTDIR)\abs_src.pdb"
+ -@erase "$(OUTDIR)\abs.exe"
+ -@erase "$(OUTDIR)\abs.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\abs_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\abs.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib $(SSLCRP).lib $(SSLLIB).lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\abs.pdb" /debug /out:"$(OUTDIR)\abs.exe" $(SSLBIN) /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\abs.obj" \
+ "$(INTDIR)\ab.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\abs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\abs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\abs.exe"
+ if exist .\Release\abs.exe.manifest mt.exe -manifest .\Release\abs.exe.manifest -outputresource:.\Release\abs.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\ab.res"
+ -@erase "$(INTDIR)\abs.obj"
+ -@erase "$(INTDIR)\abs_src.idb"
+ -@erase "$(INTDIR)\abs_src.pdb"
+ -@erase "$(OUTDIR)\abs.exe"
+ -@erase "$(OUTDIR)\abs.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\abs_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\abs.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib $(SSLCRP).lib $(SSLLIB).lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\abs.pdb" /debug /out:"$(OUTDIR)\abs.exe" $(SSLBIN)
+LINK32_OBJS= \
+ "$(INTDIR)\abs.obj" \
+ "$(INTDIR)\ab.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\abs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\abs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\abs.exe"
+ if exist .\Debug\abs.exe.manifest mt.exe -manifest .\Debug\abs.exe.manifest -outputresource:.\Debug\abs.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("abs.dep")
+!INCLUDE "abs.dep"
+!ELSE
+!MESSAGE Warning: cannot find "abs.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "abs - Win32 Release" || "$(CFG)" == "abs - Win32 Debug"
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\ab.c
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+CPP_SWITCHES=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\abs.obj" /Fd"$(INTDIR)\abs_src" /FD /c
+
+"$(INTDIR)\abs.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+CPP_SWITCHES=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\abs.obj" /Fd"$(INTDIR)\abs_src" /FD /EHsc /c
+
+"$(INTDIR)\abs.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ENDIF
+
+SOURCE=../include\ap_release.h
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+InputPath=../include\ap_release.h
+
+"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c
+<<
+
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+InputPath=../include\ap_release.h
+
+"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ <<tempfile.bat
+ @echo off
+ IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c
+<<
+
+
+!ENDIF
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "abs - Win32 Release"
+
+
+"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "abs - Win32 Debug"
+
+
+"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" $(SOURCE)
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/support/apachectl.in b/support/apachectl.in
new file mode 100644
index 0000000..3281c2e
--- /dev/null
+++ b/support/apachectl.in
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# Apache control script designed to allow an easy command line interface
+# to controlling Apache. Written by Marc Slemko, 1997/08/23
+#
+# The exit codes returned are:
+# XXX this doc is no longer correct now that the interesting
+# XXX functions are handled by httpd
+# 0 - operation completed successfully
+# 1 -
+# 2 - usage error
+# 3 - httpd could not be started
+# 4 - httpd could not be stopped
+# 5 - httpd could not be started during a restart
+# 6 - httpd could not be restarted during a restart
+# 7 - httpd could not be restarted during a graceful restart
+# 8 - configuration syntax error
+#
+# When multiple arguments are given, only the error from the _last_
+# one is reported. Run "apachectl help" for usage info
+#
+ACMD="$1"
+ARGV="$@"
+#
+# |||||||||||||||||||| START CONFIGURATION SECTION ||||||||||||||||||||
+# -------------------- --------------------
+#
+# the path to your httpd binary, including options if necessary
+HTTPD='@exp_sbindir@/@progname@'
+#
+# pick up any necessary environment variables
+if test -f @exp_sbindir@/envvars; then
+ . @exp_sbindir@/envvars
+fi
+#
+# a command that outputs a formatted text version of the HTML at the
+# url given on the command line. Designed for lynx, however other
+# programs may work.
+LYNX="@LYNX_PATH@ -dump"
+#
+# the URL to your server's mod_status status page. If you do not
+# have one, then status and fullstatus will not work.
+STATUSURL="http://localhost:@PORT@/server-status"
+#
+# Set this variable to a command that increases the maximum
+# number of file descriptors allowed per child process. This is
+# critical for configurations that use many file descriptors,
+# such as mass vhosting, or a multithreaded server.
+ULIMIT_MAX_FILES="@APACHECTL_ULIMIT@"
+# -------------------- --------------------
+# |||||||||||||||||||| END CONFIGURATION SECTION ||||||||||||||||||||
+
+# Set the maximum number of file descriptors allowed per child process.
+if [ "x$ULIMIT_MAX_FILES" != "x" ] ; then
+ $ULIMIT_MAX_FILES
+fi
+
+ERROR=0
+if [ "x$ARGV" = "x" ] ; then
+ ARGV="-h"
+fi
+
+case $ACMD in
+start|stop|restart|graceful|graceful-stop)
+ $HTTPD -k $ARGV
+ ERROR=$?
+ ;;
+startssl|sslstart|start-SSL)
+ echo The startssl option is no longer supported.
+ echo Please edit httpd.conf to include the SSL configuration settings
+ echo and then use "apachectl start".
+ ERROR=2
+ ;;
+configtest)
+ $HTTPD -t
+ ERROR=$?
+ ;;
+status)
+ $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } '
+ ;;
+fullstatus)
+ $LYNX $STATUSURL
+ ;;
+*)
+ $HTTPD "$@"
+ ERROR=$?
+esac
+
+exit $ERROR
+
diff --git a/support/apxs.in b/support/apxs.in
new file mode 100644
index 0000000..b2705fa
--- /dev/null
+++ b/support/apxs.in
@@ -0,0 +1,801 @@
+#!@perlbin@ -w
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 5.004;
+use strict;
+package apxs;
+
+##
+## Configuration
+##
+
+# are we building in a cross compile environment? If so, destdir contains
+# the base directory of the cross compiled environment, otherwise destdir
+# is the empty string.
+
+my $destdir = "";
+my $ddi = rindex($0, "@exp_bindir@");
+if ($ddi >= 0) {
+ $destdir = substr($0, 0, $ddi);
+}
+
+my %config_vars = ();
+
+my $installbuilddir = "@exp_installbuilddir@";
+get_config_vars($destdir . "$installbuilddir/config_vars.mk",\%config_vars);
+
+# read the configuration variables once
+
+my $prefix = get_vars("prefix");
+my $CFG_PREFIX = $prefix;
+my $exec_prefix = get_vars("exec_prefix");
+my $datadir = get_vars("datadir");
+my $localstatedir = get_vars("localstatedir");
+my $CFG_TARGET = get_vars("progname");
+my $CFG_SYSCONFDIR = get_vars("sysconfdir");
+my $CFG_CFLAGS = join ' ', map { get_vars($_) }
+ qw(SHLTCFLAGS CFLAGS NOTEST_CPPFLAGS EXTRA_CPPFLAGS EXTRA_CFLAGS);
+my $CFG_LDFLAGS = join ' ', map { get_vars($_) }
+ qw(LDFLAGS NOTEST_LDFLAGS SH_LDFLAGS);
+my $includedir = $destdir . get_vars("includedir");
+my $CFG_INCLUDEDIR = eval qq("$includedir");
+my $CFG_CC = get_vars("CC");
+my $libexecdir = $destdir . get_vars("libexecdir");
+my $CFG_LIBEXECDIR = eval qq("$libexecdir");
+my $sbindir = get_vars("sbindir");
+my $CFG_SBINDIR = eval qq("$sbindir");
+my $ltflags = $ENV{'LTFLAGS'};
+$ltflags or $ltflags = "--silent";
+
+my %internal_vars = map {$_ => 1}
+ qw(TARGET CC CFLAGS CFLAGS_SHLIB LD_SHLIB LDFLAGS_SHLIB LIBS_SHLIB
+ PREFIX SBINDIR INCLUDEDIR LIBEXECDIR SYSCONFDIR);
+
+##
+## parse argument line
+##
+
+# defaults for parameters
+my $opt_n = '';
+my $opt_g = '';
+my $opt_c = 0;
+my $opt_o = '';
+my @opt_D = ();
+my @opt_I = ();
+my @opt_L = ();
+my @opt_l = ();
+my @opt_W = ();
+my @opt_S = ();
+my $opt_e = 0;
+my $opt_i = 0;
+my $opt_a = 0;
+my $opt_A = 0;
+my $opt_q = 0;
+my $opt_h = 0;
+my $opt_p = 0;
+my $opt_v = 0;
+
+# this subroutine is derived from Perl's getopts.pl with the enhancement of
+# the "+" metacharacter at the format string to allow a list to be built by
+# subsequent occurrences of the same option.
+sub Getopts {
+ my ($argumentative, @ARGV) = @_;
+ my $errs = 0;
+ local $_;
+
+ my @args = split / */, $argumentative;
+ while (@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) {
+ my ($first, $rest) = ($1,$2);
+ if ($_ =~ m|^--$|) {
+ shift @ARGV;
+ last;
+ }
+ my $pos = index($argumentative,$first);
+ if ($pos >= 0) {
+ if ($pos < $#args && $args[$pos+1] eq ':') {
+ shift @ARGV;
+ if ($rest eq '') {
+ unless (@ARGV) {
+ error("Incomplete option: $first (needs an argument)");
+ $errs++;
+ }
+ $rest = shift(@ARGV);
+ }
+ eval "\$opt_$first = \$rest;";
+ }
+ elsif ($pos < $#args && $args[$pos+1] eq '+') {
+ shift @ARGV;
+ if ($rest eq '') {
+ unless (@ARGV) {
+ error("Incomplete option: $first (needs an argument)");
+ $errs++;
+ }
+ $rest = shift(@ARGV);
+ }
+ eval "push(\@opt_$first, \$rest);";
+ }
+ else {
+ eval "\$opt_$first = 1";
+ if ($rest eq '') {
+ shift(@ARGV);
+ }
+ else {
+ $ARGV[0] = "-$rest";
+ }
+ }
+ }
+ else {
+ error("Unknown option: $first");
+ $errs++;
+ if ($rest ne '') {
+ $ARGV[0] = "-$rest";
+ }
+ else {
+ shift(@ARGV);
+ }
+ }
+ }
+ return ($errs == 0, @ARGV);
+}
+
+sub usage {
+ print STDERR "Usage: apxs -g [-S <var>=<val>] -n <modname>\n";
+ print STDERR " apxs -q [-v] [-S <var>=<val>] [<query> ...]\n";
+ print STDERR " apxs -c [-S <var>=<val>] [-o <dsofile>] [-D <name>[=<value>]]\n";
+ print STDERR " [-I <incdir>] [-L <libdir>] [-l <libname>] [-Wc,<flags>]\n";
+ print STDERR " [-Wl,<flags>] [-p] <files> ...\n";
+ print STDERR " apxs -i [-S <var>=<val>] [-a] [-A] [-n <modname>] <dsofile> ...\n";
+ print STDERR " apxs -e [-S <var>=<val>] [-a] [-A] [-n <modname>] <dsofile> ...\n";
+ exit(1);
+}
+
+# option handling
+my $rc;
+($rc, @ARGV) = &Getopts("qn:gco:I+D+L+l+W+S+eiaApv", @ARGV);
+&usage if ($rc == 0);
+&usage if ($#ARGV == -1 and not $opt_g and not $opt_q);
+&usage if (not $opt_q and not ($opt_g and $opt_n) and not $opt_i and not $opt_c and not $opt_e);
+
+# argument handling
+my @args = @ARGV;
+my $name = 'unknown';
+$name = $opt_n if ($opt_n ne '');
+
+if (@opt_S) {
+ my ($opt_S);
+ foreach $opt_S (@opt_S) {
+ if ($opt_S =~ m/^([^=]+)=(.*)$/) {
+ my ($var) = $1;
+ my ($val) = $2;
+ my $oldval = eval "\$CFG_$var";
+
+ unless ($var and $oldval) {
+ print STDERR "apxs:Error: no config variable $var\n";
+ &usage;
+ }
+
+ eval "\$CFG_${var}=\"${val}\"";
+ } else {
+ print STDERR "apxs:Error: malformatted -S option\n";
+ &usage;
+ }
+ }
+}
+
+##
+## Initial shared object support check
+##
+unless ("@MOD_SO_ENABLED@" eq "yes") {
+ error("Sorry, no shared object support for Apache");
+ error("available under your platform. Make sure");
+ error("the Apache module mod_so is compiled into");
+ error("the server binary.");
+ exit 1;
+}
+
+sub get_config_vars{
+ my ($file, $rh_config) = @_;
+
+ open IN, $file or die "cannot open $file: $!";
+ while (<IN>){
+ if (/^\s*(.*?)\s*=\s*(.*)$/){
+ $rh_config->{$1} = $2;
+ }
+ }
+ close IN;
+}
+
+sub get_vars {
+ my $result = '';
+ my $ok = 0;
+ my $arg;
+ foreach $arg (@_) {
+ if (exists $config_vars{$arg} or exists $config_vars{lc $arg}) {
+ my $val = exists $config_vars{$arg}
+ ? $config_vars{$arg}
+ : $config_vars{lc $arg};
+ $val =~ s/[()]//g;
+ $result .= eval "qq($val)" if defined $val;
+ $result .= ";;";
+ $ok = 1;
+ }
+ if (not $ok) {
+ if (exists $internal_vars{$arg} or exists $internal_vars{lc $arg}) {
+ my $val = exists $internal_vars{$arg} ? $arg : lc $arg;
+ $val = eval "\$CFG_$val";
+ $result .= eval "qq($val)" if defined $val;
+ $result .= ";;";
+ $ok = 1;
+ }
+ if (not $ok) {
+ error("Invalid query string `$arg'");
+ exit(1);
+ }
+ }
+ }
+ $result =~ s|;;$||;
+ return $result;
+}
+
+##
+## Operation
+##
+
+# helper function for executing a list of
+# system command with return code checks
+sub execute_cmds {
+ my (@cmds) = @_;
+ my ($cmd, $rc);
+
+ foreach $cmd (@cmds) {
+ notice($cmd);
+ $rc = system $cmd;
+ if ($rc) {
+ error(sprintf "Command failed with rc=%d\n", $rc << 8);
+ exit 1 ;
+ }
+ }
+}
+
+if ($opt_g) {
+ ##
+ ## SAMPLE MODULE SOURCE GENERATION
+ ##
+
+ if (-d $name) {
+ error("Directory `$name' already exists. Remove first");
+ exit(1);
+ }
+
+ my $data = join('', <DATA>);
+ $data =~ s|%NAME%|$name|sg;
+ $data =~ s|%TARGET%|$CFG_TARGET|sg;
+ $data =~ s|%PREFIX%|$prefix|sg;
+ $data =~ s|%INSTALLBUILDDIR%|$installbuilddir|sg;
+
+ my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s);
+
+ notice("Creating [DIR] $name");
+ system("mkdir $name");
+ notice("Creating [FILE] $name/Makefile");
+ open(FP, ">${name}/Makefile") || die;
+ print FP $mkf;
+ close(FP);
+ notice("Creating [FILE] $name/modules.mk");
+ open(FP, ">${name}/modules.mk") || die;
+ print FP $mods;
+ close(FP);
+ notice("Creating [FILE] $name/mod_$name.c");
+ open(FP, ">${name}/mod_${name}.c") || die;
+ print FP $src;
+ close(FP);
+ notice("Creating [FILE] $name/.deps");
+ system("touch ${name}/.deps");
+
+ exit(0);
+}
+
+
+if ($opt_q) {
+ ##
+ ## QUERY INFORMATION
+ ##
+ my $result;
+ if ($#args >= 0) {
+ $result = get_vars(@args);
+ print "$result\n";
+ } else {
+ # -q without var name prints all variables and their values
+
+ # Additional -v pretty-prints output
+ if ($opt_v) {
+ # Variable names in alphabetic order
+ my @vars = sort {uc($a) cmp uc($b)} keys %config_vars;
+
+ # Make the left column as wide as the longest variable name
+ my $width = 0;
+ foreach (@vars) {
+ my $l = length $_;
+ $width = $l unless ($l <= $width);
+ }
+
+ foreach (@vars) {
+ printf "%-${width}s = %s\n", $_, $config_vars{$_};
+ }
+ } else {
+ # Unprettified name=value list
+ foreach (keys %config_vars) {
+ print "$_=$config_vars{$_}\n";
+ }
+ }
+ }
+}
+
+my $apr_config = $destdir . get_vars("APR_CONFIG");
+
+if (! -x "$apr_config") {
+ error("$apr_config not found!");
+ exit(1);
+}
+
+my $apr_major_version = (split /\./, `$apr_config --version`)[0];
+
+my $apu_config = "";
+if ($apr_major_version < 2) {
+ $apu_config = $destdir . get_vars("APU_CONFIG");
+
+ if (! -x "$apu_config") {
+ error("$apu_config not found!");
+ exit(1);
+ }
+}
+
+my $libtool = `$apr_config --apr-libtool`;
+chomp($libtool);
+
+my $apr_includedir = `$apr_config --includes`;
+chomp($apr_includedir);
+my $apu_includedir = "";
+if ($apr_major_version < 2) {
+ $apu_includedir = `$apu_config --includes`;
+ chomp($apu_includedir);
+}
+
+if ($opt_c) {
+ ##
+ ## SHARED OBJECT COMPILATION
+ ##
+
+ # split files into sources and objects
+ my @srcs = ();
+ my @objs = ();
+ my $f;
+ foreach $f (@args) {
+ if ($f =~ m|\.c$|) {
+ push(@srcs, $f);
+ }
+ else {
+ push(@objs, $f);
+ }
+ }
+
+ # determine output file
+ my $dso_file;
+ if ($opt_o eq '') {
+ if ($#srcs > -1) {
+ $dso_file = $srcs[0];
+ $dso_file =~ s|\.[^.]+$|.la|;
+ }
+ elsif ($#objs > -1) {
+ $dso_file = $objs[0];
+ $dso_file =~ s|\.[^.]+$|.la|;
+ }
+ else {
+ $dso_file = "mod_unknown.la";
+ }
+ }
+ else {
+ $dso_file = $opt_o;
+ $dso_file =~ s|\.[^.]+$|.la|;
+ }
+
+ # create compilation commands
+ my @cmds = ();
+ my $opt = '';
+ my ($opt_Wc, $opt_I, $opt_D);
+ foreach $opt_Wc (@opt_W) {
+ $opt .= "$1 " if ($opt_Wc =~ m|^\s*c,(.*)$|);
+ }
+ foreach $opt_I (@opt_I) {
+ $opt .= "-I$opt_I ";
+ }
+ foreach $opt_D (@opt_D) {
+ $opt .= "-D$opt_D ";
+ }
+ my $cflags = "$CFG_CFLAGS";
+ my $s;
+ my $mod;
+ foreach $s (@srcs) {
+ my $slo = $s;
+ $slo =~ s|\.c$|.slo|;
+ my $lo = $s;
+ $lo =~ s|\.c$|.lo|;
+ my $la = $s;
+ $la =~ s|\.c$|.la|;
+ my $o = $s;
+ $o =~ s|\.c$|.o|;
+ push(@cmds, "$libtool $ltflags --mode=compile $CFG_CC $cflags -I$CFG_INCLUDEDIR $apr_includedir $apu_includedir $opt -c -o $lo $s && touch $slo");
+ unshift(@objs, $lo);
+ }
+
+ # create link command
+ my $o;
+ my $lo;
+ foreach $o (@objs) {
+ $lo .= " $o";
+ }
+ my ($opt_Wl, $opt_L, $opt_l);
+ $opt = '';
+ foreach $opt_Wl (@opt_W) {
+ $opt .= "$1 " if ($opt_Wl =~ m|^\s*l,(.*)$|);
+ }
+ foreach $opt_L (@opt_L) {
+ $opt .= " -L$opt_L";
+ }
+ foreach $opt_l (@opt_l) {
+ $opt .= " -l$opt_l";
+ }
+
+ my $ldflags = "$CFG_LDFLAGS";
+ if ($opt_p == 1) {
+
+ my $apr_libs=`$apr_config --cflags --ldflags --link-libtool --libs`;
+ chomp($apr_libs);
+ my $apu_libs="";
+ if ($apr_major_version < 2) {
+ $apu_libs=`$apu_config --ldflags --link-libtool --libs`;
+ chomp($apu_libs);
+ }
+
+ $opt .= " ".$apu_libs." ".$apr_libs;
+ }
+ else {
+ my $apr_ldflags=`$apr_config --ldflags`;
+ chomp($apr_ldflags);
+ $opt .= " -rpath $CFG_LIBEXECDIR -module -avoid-version $apr_ldflags";
+ }
+
+ push(@cmds, "$libtool $ltflags --mode=link $CFG_CC $ldflags -o $dso_file $opt $lo");
+
+ # execute the commands
+ &execute_cmds(@cmds);
+
+ # allow one-step compilation and installation
+ if ($opt_i or $opt_e) {
+ @args = ( $dso_file );
+ }
+}
+
+if ($opt_i or $opt_e) {
+ ##
+ ## SHARED OBJECT INSTALLATION
+ ##
+
+ # determine installation commands
+ # and corresponding LoadModule directive
+ my @lmd = ();
+ my @cmds = ();
+ my $f;
+ foreach $f (@args) {
+ # ack all potential gcc, hp/ux, win32+os2+aix and os/x extensions
+ if ($f !~ m#(\.so$|\.la$|\.sl$|\.dll$|\.dylib$|)#) {
+ error("file $f is not a shared object");
+ exit(1);
+ }
+ my $t = $f;
+ $t =~ s|^.+/([^/]+)$|$1|;
+ # use .so unambigiously for installed shared library modules
+ $t =~ s|\.[^./\\]+$|\.so|;
+ if ($opt_i) {
+ push(@cmds, $destdir . "$installbuilddir/instdso.sh SH_LIBTOOL='" .
+ "$libtool' $f $CFG_LIBEXECDIR");
+ push(@cmds, "chmod 755 $CFG_LIBEXECDIR/$t");
+ }
+
+ # determine module symbolname and filename
+ my $filename = '';
+ if ($name eq 'unknown') {
+ $name = '';
+ my $base = $f;
+ $base =~ s|\.[^.]+$||;
+ if (-f "$base.c") {
+ open(FP, "<$base.c");
+ my $content = join('', <FP>);
+ close(FP);
+ if ($content =~ m|.*AP_DECLARE_MODULE\s*\(\s*([a-zA-Z0-9_]+)\s*\)\s*=.*|s || $content =~ m|.*module\s+(?:AP_MODULE_DECLARE_DATA\s+)?([a-zA-Z0-9_]+)_module\s*=\s*.*|s) {
+ $name = "$1";
+ $filename = "$base.c";
+ $filename =~ s|^[^/]+/||;
+ }
+ }
+ if ($name eq '') {
+ if ($base =~ m|.*mod_([a-zA-Z0-9_]+)\..+|) {
+ $name = "$1";
+ $filename = $base;
+ $filename =~ s|^[^/]+/||;
+ }
+ }
+ if ($name eq '') {
+ error("Sorry, cannot determine bootstrap symbol name");
+ error("Please specify one with option `-n'");
+ exit(1);
+ }
+ }
+ if ($filename eq '') {
+ $filename = "mod_${name}.c";
+ }
+ my $dir = $CFG_LIBEXECDIR;
+ $dir =~ s|^$CFG_PREFIX/?||;
+ $dir =~ s|(.)$|$1/|;
+ $t =~ s|\.la$|.so|;
+ push(@lmd, sprintf("LoadModule %-18s %s", "${name}_module", "$dir$t"));
+ }
+
+ # execute the commands
+ &execute_cmds(@cmds);
+
+ # activate module via LoadModule/AddModule directive
+ if ($opt_a or $opt_A) {
+ if (not -f "$CFG_SYSCONFDIR/$CFG_TARGET.conf") {
+ error("Config file $CFG_SYSCONFDIR/$CFG_TARGET.conf not found");
+ exit(1);
+ }
+
+ open(FP, "<$CFG_SYSCONFDIR/$CFG_TARGET.conf") || die;
+ my $content = join('', <FP>);
+ close(FP);
+
+ if ($content !~ m|\n#?\s*LoadModule\s+|) {
+ error("Activation failed for custom $CFG_SYSCONFDIR/$CFG_TARGET.conf file.");
+ error("At least one `LoadModule' directive already has to exist.");
+ exit(1);
+ }
+
+ my $lmd;
+ my $c = '';
+ $c = '#' if ($opt_A);
+ foreach $lmd (@lmd) {
+ my $what = $opt_A ? "preparing" : "activating";
+ my $lmd_re = $lmd;
+ $lmd_re =~ s/\s+/\\s+/g;
+
+ if ($content !~ m|\n#?\s*$lmd_re|) {
+ # check for open <containers>, so that the new LoadModule
+ # directive always appears *outside* of an <container>.
+
+ my $before = ($content =~ m|^(.*\n)#?\s*LoadModule\s+[^\n]+\n|s)[0];
+
+ # the '()=' trick forces list context and the scalar
+ # assignment counts the number of list members (aka number
+ # of matches) then
+ my $cntopen = () = ($before =~ m|^\s*<[^/].*$|mg);
+ my $cntclose = () = ($before =~ m|^\s*</.*$|mg);
+
+ if ($cntopen == $cntclose) {
+ # fine. Last LoadModule is contextless.
+ $content =~ s|^(.*\n#?\s*LoadModule\s+[^\n]+\n)|$1$c$lmd\n|s;
+ }
+ elsif ($cntopen < $cntclose) {
+ error('Configuration file is not valid. There are sections'
+ . ' closed before opened.');
+ exit(1);
+ }
+ else {
+ # put our cmd after the section containing the last
+ # LoadModule.
+ my $found =
+ $content =~ s!\A ( # string and capture start
+ (?:(?:
+ ^\s* # start of conf line with a
+ (?:[^<]|<[^/]) # directive which does not
+ # start with '</'
+
+ .*(?:$)\n # rest of the line.
+ # the '$' is in parentheses
+ # to avoid misinterpreting
+ # the string "$\" as
+ # perl variable.
+
+ )* # catch as much as possible
+ # of such lines. (including
+ # zero)
+
+ ^\s*</.*(?:$)\n? # after the above, we
+ # expect a config line with
+ # a closing container (</)
+
+ ) {$cntopen} # the whole pattern (bunch
+ # of lines that end up with
+ # a closing directive) must
+ # be repeated $cntopen
+ # times. That's it.
+ # Simple, eh? ;-)
+
+ ) # capture end
+ !$1$c$lmd\n!mx;
+
+ unless ($found) {
+ error('Configuration file is not valid. There are '
+ . 'sections opened and not closed.');
+ exit(1);
+ }
+ }
+ } else {
+ # replace already existing LoadModule line
+ $content =~ s|^(.*\n)#?\s*$lmd_re[^\n]*\n|$1$c$lmd\n|s;
+ }
+ $lmd =~ m|LoadModule\s+(.+?)_module.*|;
+ notice("[$what module `$1' in $CFG_SYSCONFDIR/$CFG_TARGET.conf]");
+ }
+ if (@lmd) {
+ if (open(FP, ">$CFG_SYSCONFDIR/$CFG_TARGET.conf.new")) {
+ print FP $content;
+ close(FP);
+ system("cp $CFG_SYSCONFDIR/$CFG_TARGET.conf $CFG_SYSCONFDIR/$CFG_TARGET.conf.bak && " .
+ "cp $CFG_SYSCONFDIR/$CFG_TARGET.conf.new $CFG_SYSCONFDIR/$CFG_TARGET.conf && " .
+ "rm $CFG_SYSCONFDIR/$CFG_TARGET.conf.new");
+ } else {
+ notice("unable to open configuration file");
+ }
+ }
+ }
+}
+
+sub error{
+ print STDERR "apxs:Error: $_[0].\n";
+}
+
+sub notice{
+ print STDERR "$_[0]\n";
+}
+
+##EOF##
+__DATA__
+##
+## Makefile -- Build procedure for sample %NAME% Apache module
+## Autogenerated via ``apxs -n %NAME% -g''.
+##
+
+builddir=.
+top_srcdir=%PREFIX%
+top_builddir=%PREFIX%
+include %INSTALLBUILDDIR%/special.mk
+
+# the used tools
+APACHECTL=apachectl
+
+# additional defines, includes and libraries
+#DEFS=-Dmy_define=my_value
+#INCLUDES=-Imy/include/dir
+#LIBS=-Lmy/lib/dir -lmylib
+
+# the default target
+all: local-shared-build
+
+# install the shared object file into Apache
+install: install-modules-yes
+
+# cleanup
+clean:
+ -rm -f mod_%NAME%.o mod_%NAME%.lo mod_%NAME%.slo mod_%NAME%.la
+
+# simple test
+test: reload
+ lynx -mime_header http://localhost/%NAME%
+
+# install and activate shared object by reloading Apache to
+# force a reload of the shared object file
+reload: install restart
+
+# the general Apache start/restart/stop
+# procedures
+start:
+ $(APACHECTL) start
+restart:
+ $(APACHECTL) restart
+stop:
+ $(APACHECTL) stop
+
+-=#=-
+mod_%NAME%.la: mod_%NAME%.slo
+ $(SH_LINK) -rpath $(libexecdir) -module -avoid-version mod_%NAME%.lo
+DISTCLEAN_TARGETS = modules.mk
+shared = mod_%NAME%.la
+-=#=-
+/*
+** mod_%NAME%.c -- Apache sample %NAME% module
+** [Autogenerated via ``apxs -n %NAME% -g'']
+**
+** To play with this sample module first compile it into a
+** DSO file and install it into Apache's modules directory
+** by running:
+**
+** $ apxs -c -i mod_%NAME%.c
+**
+** Then activate it in Apache's %TARGET%.conf file for instance
+** for the URL /%NAME% in as follows:
+**
+** # %TARGET%.conf
+** LoadModule %NAME%_module modules/mod_%NAME%.so
+** <Location /%NAME%>
+** SetHandler %NAME%
+** </Location>
+**
+** Then after restarting Apache via
+**
+** $ apachectl restart
+**
+** you immediately can request the URL /%NAME% and watch for the
+** output of this module. This can be achieved for instance via:
+**
+** $ lynx -mime_header http://localhost/%NAME%
+**
+** The output should be similar to the following one:
+**
+** HTTP/1.1 200 OK
+** Date: Tue, 31 Mar 1998 14:42:22 GMT
+** Server: Apache/1.3.4 (Unix)
+** Connection: close
+** Content-Type: text/html
+**
+** The sample page from mod_%NAME%.c
+*/
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_protocol.h"
+#include "ap_config.h"
+
+/* The sample content handler */
+static int %NAME%_handler(request_rec *r)
+{
+ if (strcmp(r->handler, "%NAME%")) {
+ return DECLINED;
+ }
+ r->content_type = "text/html";
+
+ if (!r->header_only)
+ ap_rputs("The sample page from mod_%NAME%.c\n", r);
+ return OK;
+}
+
+static void %NAME%_register_hooks(apr_pool_t *p)
+{
+ ap_hook_handler(%NAME%_handler, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+/* Dispatch list for API hooks */
+module AP_MODULE_DECLARE_DATA %NAME%_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-dir config structures */
+ NULL, /* merge per-dir config structures */
+ NULL, /* create per-server config structures */
+ NULL, /* merge per-server config structures */
+ NULL, /* table of config file commands */
+ %NAME%_register_hooks /* register hooks */
+};
+
diff --git a/support/check_forensic b/support/check_forensic
new file mode 100755
index 0000000..d7a3f78
--- /dev/null
+++ b/support/check_forensic
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# check_forensic <forensic log file>
+
+# check the forensic log for requests that did not complete
+# output the request log for each one
+
+F=$1
+
+temp_create_method=file
+if test -f `which mktemp`; then
+ temp_create_method=mktemp
+elif test -f `which tempfile`; then
+ temp_create_method=tempfile
+fi
+
+create_temp()
+{
+ prefix=$1
+ case "$temp_create_method" in
+ file)
+ name="/tmp/$1.$$"
+ ;;
+ mktemp)
+ name=`mktemp -t $1.XXXXXX`
+ ;;
+ tempfile)
+ name=`tempfile --prefix=$1`
+ ;;
+ *)
+ echo "$0: Cannot create temporary file"
+ exit 1
+ ;;
+ esac
+}
+
+create_temp fcall
+all=$name
+create_temp fcin
+in=$name
+create_temp fcout
+out=$name
+trap "rm -f -- \"$all\" \"$in\" \"$out\";" 0 1 2 3 13 15
+
+cut -f 1 -d '|' $F > $all
+grep ^+ < $all | cut -c2- | sort > $in
+grep -- ^- < $all | cut -c2- | sort > $out
+
+# use -i instead of -I for GNU xargs
+join -v 1 $in $out | xargs -I xx egrep "^\\+xx" $F
+exit 0
diff --git a/support/checkgid.c b/support/checkgid.c
new file mode 100644
index 0000000..29de650
--- /dev/null
+++ b/support/checkgid.c
@@ -0,0 +1,110 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Given one or more group identifiers on the command line (e.g.,
+ * "httpd" or "#-1"), figure out whether they'll be valid for
+ * the server to use at run-time.
+ *
+ * If a groupname isn't found, or we can't setgid() to it, return
+ * -1. If all groups are valid, return 0.
+ *
+ * This may need to be run as the superuser for the setgid() to
+ * succeed; running it as any other user may result in a false
+ * negative.
+ */
+
+#include "ap_config.h"
+#if APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_GRP_H
+#include <grp.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int result;
+ gid_t gid;
+ struct group *grent;
+ struct group fake_grent;
+
+ /*
+ * Assume success. :-)
+ */
+ result = 0;
+ for (i = 1; i < argc; ++i) {
+ char *arg;
+ arg = argv[i];
+
+ /*
+ * If it's from a 'Group #-1' statement, get the numeric value
+ * and skip the group lookup stuff.
+ */
+ if (*arg == '#') {
+ gid = atoi(&arg[1]);
+ fake_grent.gr_gid = gid;
+ grent = &fake_grent;
+ }
+ else {
+ grent = getgrnam(arg);
+ }
+
+ /*
+ * A NULL return means no such group was found, so we're done
+ * with this one.
+ */
+ if (grent == NULL) {
+ fprintf(stderr, "%s: group '%s' not found\n", argv[0], arg);
+ result = -1;
+ }
+ else {
+ int check;
+
+ /*
+ * See if we can switch to the numeric GID we have. If so,
+ * all well and good; if not, well..
+ */
+ gid = grent->gr_gid;
+ check = setgid(gid);
+ if (check != 0) {
+ fprintf(stderr, "%s: invalid group '%s'\n", argv[0], arg);
+ perror(argv[0]);
+ result = -1;
+ }
+ }
+ }
+ /*
+ * Worst-case return value.
+ */
+ return result;
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/support/config.m4 b/support/config.m4
new file mode 100644
index 0000000..4865e38
--- /dev/null
+++ b/support/config.m4
@@ -0,0 +1,151 @@
+htpasswd_LTFLAGS=""
+htdigest_LTFLAGS=""
+rotatelogs_LTFLAGS=""
+logresolve_LTFLAGS=""
+htdbm_LTFLAGS=""
+ab_LTFLAGS=""
+checkgid_LTFLAGS=""
+htcacheclean_LTFLAGS=""
+httxt2dbm_LTFLAGS=""
+fcgistarter_LTFLAGS=""
+
+AC_ARG_ENABLE(static-support,APACHE_HELP_STRING(--enable-static-support,Build a statically linked version of the support binaries),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(htpasswd_LTFLAGS, [-static])
+ APR_ADDTO(htdigest_LTFLAGS, [-static])
+ APR_ADDTO(rotatelogs_LTFLAGS, [-static])
+ APR_ADDTO(logresolve_LTFLAGS, [-static])
+ APR_ADDTO(htdbm_LTFLAGS, [-static])
+ APR_ADDTO(ab_LTFLAGS, [-static])
+ APR_ADDTO(checkgid_LTFLAGS, [-static])
+ APR_ADDTO(htcacheclean_LTFLAGS, [-static])
+ APR_ADDTO(httxt2dbm_LTFLAGS, [-static])
+ APR_ADDTO(fcgistarter_LTFLAGS, [-static])
+fi
+])
+
+AC_ARG_ENABLE(static-htpasswd,APACHE_HELP_STRING(--enable-static-htpasswd,Build a statically linked version of htpasswd),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(htpasswd_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(htpasswd_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(htpasswd_LTFLAGS)
+
+AC_ARG_ENABLE(static-htdigest,APACHE_HELP_STRING(--enable-static-htdigest,Build a statically linked version of htdigest),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(htdigest_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(htdigest_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(htdigest_LTFLAGS)
+
+AC_ARG_ENABLE(static-rotatelogs,APACHE_HELP_STRING(--enable-static-rotatelogs,Build a statically linked version of rotatelogs),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(rotatelogs_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(rotatelogs_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(rotatelogs_LTFLAGS)
+
+AC_ARG_ENABLE(static-logresolve,APACHE_HELP_STRING(--enable-static-logresolve,Build a statically linked version of logresolve),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(logresolve_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(logresolve_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(logresolve_LTFLAGS)
+
+AC_ARG_ENABLE(static-htdbm,APACHE_HELP_STRING(--enable-static-htdbm,Build a statically linked version of htdbm),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(htdbm_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(htdbm_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(htdbm_LTFLAGS)
+
+AC_ARG_ENABLE(static-ab,APACHE_HELP_STRING(--enable-static-ab,Build a statically linked version of ab),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(ab_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(ab_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(ab_LTFLAGS)
+
+AC_ARG_ENABLE(static-checkgid,APACHE_HELP_STRING(--enable-static-checkgid,Build a statically linked version of checkgid),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(checkgid_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(checkgid_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(checkgid_LTFLAGS)
+
+AC_ARG_ENABLE(static-htcacheclean,APACHE_HELP_STRING(--enable-static-htcacheclean,Build a statically linked version of htcacheclean),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(htcacheclean_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(htcacheclean_LTFLAGS, [-static])
+fi
+])
+APACHE_SUBST(htcacheclean_LTFLAGS)
+
+AC_ARG_ENABLE(static-httxt2dbm,APACHE_HELP_STRING(--enable-static-httxt2dbm,Build a statically linked version of httxt2dbm),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(httxt2dbm_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(httxt2dbm, [-static])
+fi
+])
+APACHE_SUBST(httxt2dbm_LTFLAGS)
+
+AC_ARG_ENABLE(static-fcgistarter,APACHE_HELP_STRING(--enable-static-fcgistarter,Build a statically linked version of fcgistarter),[
+if test "$enableval" = "yes" ; then
+ APR_ADDTO(fcgistarter_LTFLAGS, [-static])
+else
+ APR_REMOVEFROM(fcgistarter, [-static])
+fi
+])
+APACHE_SUBST(fcgistarter_LTFLAGS)
+
+# Configure or check which of the non-portable support programs can be enabled.
+
+NONPORTABLE_SUPPORT=""
+case $host in
+ *mingw*)
+ ;;
+ *)
+ NONPORTABLE_SUPPORT="checkgid fcgistarter"
+ ;;
+esac
+APACHE_SUBST(NONPORTABLE_SUPPORT)
+
+# Configure the ulimit -n command used by apachectl.
+
+case $host in
+ *aix*)
+ # this works in any locale, unlike the default command below, which
+ # fails in a non-English locale if the hard limit is unlimited
+ # since the display of the limit will translate "unlimited", but
+ # ulimit only accepts English "unlimited" on input
+ APACHECTL_ULIMIT="ulimit -S -n unlimited"
+ ;;
+ *alpha*-dec-osf*)
+ # Tru64: -H is for setting, not retrieving
+ APACHECTL_ULIMIT="ulimit -S -n \`ulimit -h -n\`"
+ ;;
+ *)
+ if TMP_ULIMIT=`ulimit -H -n` && ulimit -S -n $TMP_ULIMIT >/dev/null 2>&1; then
+ APACHECTL_ULIMIT="ulimit -S -n \`ulimit -H -n\`"
+ else
+ APACHECTL_ULIMIT=""
+ fi
+ ;;
+esac
+APACHE_SUBST(APACHECTL_ULIMIT)
diff --git a/support/dbmmanage.in b/support/dbmmanage.in
new file mode 100644
index 0000000..2dd8c86
--- /dev/null
+++ b/support/dbmmanage.in
@@ -0,0 +1,312 @@
+#!@perlbin@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#for more functionality see the HTTPD::UserAdmin module:
+# http://www.perl.com/CPAN/modules/by-module/HTTPD/HTTPD-Tools-x.xx.tar.gz
+#
+# usage: dbmmanage <DBMfile> <command> <user> <password> <groups> <comment>
+
+package dbmmanage;
+# -ldb -lndbm -lgdbm -lsdbm
+BEGIN { @AnyDBM_File::ISA = qw(DB_File NDBM_File GDBM_File SDBM_File) }
+use strict;
+use Fcntl;
+use AnyDBM_File ();
+
+sub usage {
+ my $cmds = join "|", sort keys %dbmc::;
+ die <<SYNTAX;
+Usage: dbmmanage [enc] dbname command [username [pw [group[,group] [comment]]]]
+
+ where enc is -d for crypt encryption (default except on Win32, Netware)
+ -m for MD5 encryption (default on Win32, Netware)
+ -s for SHA1 encryption
+ -p for plaintext
+
+ command is one of: $cmds
+
+ pw of . for update command retains the old password
+ pw of - (or blank) for update command prompts for the password
+
+ groups or comment of . (or blank) for update command retains old values
+ groups or comment of - for update command clears the existing value
+ groups or comment of - for add and adduser commands is the empty value
+SYNTAX
+}
+
+sub need_sha1_crypt {
+ if (!eval ('require "Digest/SHA1.pm";')) {
+ print STDERR <<SHAERR;
+dbmmanage SHA1 passwords require the interface or the module Digest::SHA1
+available from CPAN:
+
+ http://www.cpan.org/modules/by-module/Digest/Digest-MD5-2.12.tar.gz
+
+Please install Digest::SHA1 and try again, or use a different crypt option:
+
+SHAERR
+ usage();
+ }
+}
+
+sub need_md5_crypt {
+ if (!eval ('require "Crypt/PasswdMD5.pm";')) {
+ print STDERR <<MD5ERR;
+dbmmanage MD5 passwords require the module Crypt::PasswdMD5 available from CPAN
+
+ http://www.cpan.org/modules/by-module/Crypt/Crypt-PasswdMD5-1.1.tar.gz
+
+Please install Crypt::PasswdMD5 and try again, or use a different crypt option:
+
+MD5ERR
+ usage();
+ }
+}
+
+# if your osname is in $newstyle_salt, then use new style salt (starts with '_' and contains
+# four bytes of iteration count and four bytes of salt). Otherwise, just use
+# the traditional two-byte salt.
+# see the man page on your system to decide if you have a newer crypt() lib.
+# I believe that 4.4BSD derived systems do (at least BSD/OS 2.0 does).
+# The new style crypt() allows up to 20 characters of the password to be
+# significant rather than only 8.
+#
+my $newstyle_salt_platforms = join '|', qw{bsdos}; #others?
+my $newstyle_salt = $^O =~ /(?:$newstyle_salt_platforms)/;
+
+# Some platforms just can't crypt() for Apache
+#
+my $crypt_not_supported_platforms = join '|', qw{MSWin32 NetWare}; #others?
+my $crypt_not_supported = $^O =~ /(?:$crypt_not_supported_platforms)/;
+
+my $crypt_method = "crypt";
+
+if ($crypt_not_supported) {
+ $crypt_method = "md5";
+}
+
+# Some platforms won't jump through our favorite hoops
+#
+my $not_unix_platforms = join '|', qw{MSWin32 NetWare}; #others?
+my $not_unix = $^O =~ /(?:$not_unix_platforms)/;
+
+if ($crypt_not_supported) {
+ $crypt_method = "md5";
+}
+
+if (@ARGV[0] eq "-d") {
+ shift @ARGV;
+ if ($crypt_not_supported) {
+ print STDERR
+ "Warning: Apache/$^O does not support crypt()ed passwords!\n\n";
+ }
+ $crypt_method = "crypt";
+}
+
+if (@ARGV[0] eq "-m") {
+ shift @ARGV;
+ $crypt_method = "md5";
+}
+
+if (@ARGV[0] eq "-p") {
+ shift @ARGV;
+ if (!$crypt_not_supported) {
+ print STDERR
+ "Warning: Apache/$^O does not support plaintext passwords!\n\n";
+ }
+ $crypt_method = "plain";
+}
+
+if (@ARGV[0] eq "-s") {
+ shift @ARGV;
+ need_sha1_crypt();
+ $crypt_method = "sha1";
+}
+
+if ($crypt_method eq "md5") {
+ need_md5_crypt();
+}
+
+my($file,$command,$key,$crypted_pwd,$groups,$comment) = @ARGV;
+
+usage() unless $file and $command and defined &{$dbmc::{$command}};
+
+# remove extension if any
+my $chop = join '|', qw{db.? pag dir};
+$file =~ s/\.($chop)$//;
+
+my $is_update = $command eq "update";
+my %DB = ();
+my @range = ();
+my($mode, $flags) = $command =~
+ /^(?:view|check)$/ ? (0644, O_RDONLY) : (0644, O_RDWR|O_CREAT);
+
+tie (%DB, "AnyDBM_File", $file, $flags, $mode) || die "Can't tie $file: $!";
+dbmc->$command();
+untie %DB;
+
+
+my $x;
+sub genseed {
+ my $psf;
+ if ($not_unix) {
+ srand (time ^ $$ or time ^ ($$ + ($$ << 15)));
+ }
+ else {
+ for (qw(-xlwwa -le)) {
+ `ps $_ 2>/dev/null`;
+ $psf = $_, last unless $?;
+ }
+ srand (time ^ $$ ^ unpack("%L*", `ps $psf | gzip -f`));
+ }
+ @range = (qw(. /), '0'..'9','a'..'z','A'..'Z');
+ $x = int scalar @range;
+}
+
+sub randchar {
+ join '', map $range[rand $x], 1..shift||1;
+}
+
+sub saltpw_crypt {
+ genseed() unless @range;
+ return $newstyle_salt ?
+ join '', "_", randchar, "a..", randchar(4) :
+ randchar(2);
+}
+
+sub cryptpw_crypt {
+ my ($pw, $salt) = @_;
+ $salt = saltpw_crypt unless $salt;
+ crypt $pw, $salt;
+}
+
+sub saltpw_md5 {
+ genseed() unless @range;
+ randchar(8);
+}
+
+sub cryptpw_md5 {
+ my($pw, $salt) = @_;
+ $salt = saltpw_md5 unless $salt;
+ Crypt::PasswdMD5::apache_md5_crypt($pw, $salt);
+}
+
+sub cryptpw_sha1 {
+ my($pw, $salt) = @_;
+ '{SHA}' . Digest::SHA1::sha1_base64($pw) . "=";
+}
+
+sub cryptpw {
+ if ($crypt_method eq "md5") {
+ return cryptpw_md5(@_);
+ } elsif ($crypt_method eq "sha1") {
+ return cryptpw_sha1(@_);
+ } elsif ($crypt_method eq "crypt") {
+ return cryptpw_crypt(@_);
+ }
+ @_[0]; # otherwise return plaintext
+}
+
+sub getpass {
+ my $prompt = shift || "Enter password:";
+
+ unless($not_unix) {
+ open STDIN, "/dev/tty" or warn "couldn't open /dev/tty $!\n";
+ system "stty -echo;";
+ }
+
+ my($c,$pwd);
+ print STDERR $prompt;
+ while (($c = getc(STDIN)) ne '' and $c ne "\n" and $c ne "\r") {
+ $pwd .= $c;
+ }
+
+ system "stty echo" unless $not_unix;
+ print STDERR "\n";
+ die "Can't use empty password!\n" unless length $pwd;
+ return $pwd;
+}
+
+sub dbmc::update {
+ die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key};
+ $crypted_pwd = (split /:/, $DB{$key}, 3)[0] if $crypted_pwd eq '.';
+ $groups = (split /:/, $DB{$key}, 3)[1] if !$groups || $groups eq '.';
+ $comment = (split /:/, $DB{$key}, 3)[2] if !$comment || $comment eq '.';
+ if (!$crypted_pwd || $crypted_pwd eq '-') {
+ dbmc->adduser;
+ }
+ else {
+ dbmc->add;
+ }
+}
+
+sub dbmc::add {
+ die "Can't use empty password!\n" unless $crypted_pwd;
+ unless($is_update) {
+ die "Sorry, user `$key' already exists!\n" if $DB{$key};
+ }
+ $groups = '' if $groups eq '-';
+ $comment = '' if $comment eq '-';
+ $groups .= ":" . $comment if $comment;
+ $crypted_pwd .= ":" . $groups if $groups;
+ $DB{$key} = $crypted_pwd;
+ my $action = $is_update ? "updated" : "added";
+ print "User $key $action with password encrypted to $DB{$key} using $crypt_method\n";
+}
+
+sub dbmc::adduser {
+ my $value = getpass "New password:";
+ die "They don't match, sorry.\n" unless getpass("Re-type new password:") eq $value;
+ $crypted_pwd = cryptpw $value;
+ dbmc->add;
+}
+
+sub dbmc::delete {
+ die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key};
+ delete $DB{$key}, print "`$key' deleted\n";
+}
+
+sub dbmc::view {
+ print $key ? "$key:$DB{$key}\n" : map { "$_:$DB{$_}\n" if $DB{$_} } keys %DB;
+}
+
+sub dbmc::check {
+ die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key};
+ my $chkpass = (split /:/, $DB{$key}, 3)[0];
+ my $testpass = getpass();
+ if (substr($chkpass, 0, 6) eq '$apr1$') {
+ need_md5_crypt;
+ $crypt_method = "md5";
+ } elsif (substr($chkpass, 0, 5) eq '{SHA}') {
+ need_sha1_crypt;
+ $crypt_method = "sha1";
+ } elsif (length($chkpass) == 13 && $chkpass ne $testpass) {
+ $crypt_method = "crypt";
+ } else {
+ $crypt_method = "plain";
+ }
+ print $crypt_method . (cryptpw($testpass, $chkpass) eq $chkpass
+ ? " password ok\n" : " password mismatch\n");
+}
+
+sub dbmc::import {
+ while(defined($_ = <STDIN>) and chomp) {
+ ($key,$crypted_pwd,$groups,$comment) = split /:/, $_, 4;
+ dbmc->add;
+ }
+}
+
diff --git a/support/envvars-std.in b/support/envvars-std.in
new file mode 100644
index 0000000..9493bc7
--- /dev/null
+++ b/support/envvars-std.in
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# envvars-std - default environment variables for apachectl
+#
+# This file is generated from envvars-std.in
+#
+if test "x$@SHLIBPATH_VAR@" != "x" ; then
+ @SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@"
+else
+ @SHLIBPATH_VAR@="@exp_libdir@"
+fi
+export @SHLIBPATH_VAR@
+#
+@OS_SPECIFIC_VARS@
diff --git a/support/fcgistarter.c b/support/fcgistarter.c
new file mode 100644
index 0000000..9cfda51
--- /dev/null
+++ b/support/fcgistarter.c
@@ -0,0 +1,220 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_network_io.h>
+#include <apr_thread_proc.h>
+#include <apr_getopt.h>
+#include <apr_portable.h>
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h> /* For EXIT_SUCCESS, EXIT_FAILURE */
+#endif
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h> /* For execl */
+#endif
+
+static const char *usage_message =
+ "usage: fcgistarter -c <command> -p <port> [-i <interface> -N <num>]\n"
+ "\n"
+ "If an interface is not specified, any available will be used.\n";
+
+static void usage(void)
+{
+ fprintf(stderr, "%s", usage_message);
+
+ exit(EXIT_FAILURE);
+}
+
+static void exit_error(apr_status_t rv, const char *func)
+{
+ char buffer[1024];
+
+ fprintf(stderr,
+ "%s: %s\n",
+ func,
+ apr_strerror(rv, buffer, sizeof(buffer)));
+
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, const char * const argv[])
+{
+ apr_file_t *infd, *skwrapper;
+ apr_sockaddr_t *skaddr;
+ apr_getopt_t *gopt;
+ apr_socket_t *skt;
+ apr_pool_t *pool;
+ apr_status_t rv;
+ apr_proc_t proc;
+
+
+ /* Command line arguments */
+ int num_to_start = 1, port = 0;
+ const char *interface = NULL;
+ const char *command = NULL;
+
+ apr_app_initialize(&argc, &argv, NULL);
+
+ atexit(apr_terminate);
+
+ apr_pool_create(&pool, NULL);
+
+ rv = apr_getopt_init(&gopt, pool, argc, argv);
+ if (rv) {
+ return EXIT_FAILURE;
+ }
+
+ for (;;) {
+ const char *arg;
+ char opt;
+
+ rv = apr_getopt(gopt, "c:p:i:N:", &opt, &arg);
+ if (APR_STATUS_IS_EOF(rv)) {
+ break;
+ } else if (rv) {
+ usage();
+ } else {
+ switch (opt) {
+ case 'c':
+ command = arg;
+ break;
+
+ case 'p':
+ port = atoi(arg);
+ if (! port) {
+ usage();
+ }
+ break;
+
+ case 'i':
+ interface = arg;
+ break;
+
+ case 'N':
+ num_to_start = atoi(arg);
+ if (! num_to_start) {
+ usage();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (! command || ! port) {
+ usage();
+ }
+
+ rv = apr_sockaddr_info_get(&skaddr, interface, APR_UNSPEC, port, 0, pool);
+ if (rv) {
+ exit_error(rv, "apr_sockaddr_info_get");
+ }
+
+ rv = apr_socket_create(&skt, skaddr->family, SOCK_STREAM, APR_PROTO_TCP, pool);
+ if (rv) {
+ exit_error(rv, "apr_socket_create");
+ }
+
+ rv = apr_socket_opt_set(skt, APR_SO_REUSEADDR, 1);
+ if (rv) {
+ exit_error(rv, "apr_socket_opt_set(APR_SO_REUSEADDR)");
+ }
+
+ rv = apr_socket_bind(skt, skaddr);
+ if (rv) {
+ exit_error(rv, "apr_socket_bind");
+ }
+
+ rv = apr_socket_listen(skt, 1024);
+ if (rv) {
+ exit_error(rv, "apr_socket_listen");
+ }
+
+ rv = apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
+ if (rv) {
+ exit_error(rv, "apr_proc_detach");
+ }
+
+#if defined(WIN32) || defined(OS2) || defined(NETWARE)
+
+#error "Please implement me."
+
+#else
+
+ while (--num_to_start >= 0) {
+ rv = apr_proc_fork(&proc, pool);
+ if (rv == APR_INCHILD) {
+ apr_os_file_t oft = 0;
+ apr_os_sock_t oskt;
+
+ /* Ok, so we need a file that has file descriptor 0 (which
+ * FastCGI wants), but points to our socket. This isn't really
+ * possible in APR, so we cheat a bit. I have no idea how to
+ * do this on a non-unix platform, so for now this is platform
+ * specific. Ick.
+ *
+ * Note that this has to happen post-detach, otherwise fd 0
+ * gets closed during apr_proc_detach and it's all for nothing.
+ *
+ * Unfortunately, doing this post detach means we have no way
+ * to let anyone know if there's a problem at this point :( */
+
+ rv = apr_os_file_put(&infd, &oft, APR_READ | APR_WRITE, pool);
+ if (rv) {
+ exit(EXIT_FAILURE);
+ }
+
+ rv = apr_os_sock_get(&oskt, skt);
+ if (rv) {
+ exit(EXIT_FAILURE);
+ }
+
+ rv = apr_os_file_put(&skwrapper, &oskt, APR_READ | APR_WRITE,
+ pool);
+ if (rv) {
+ exit(EXIT_FAILURE);
+ }
+
+ rv = apr_file_dup2(infd, skwrapper, pool);
+ if (rv) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* XXX Can't use apr_proc_create because there's no way to get
+ * infd into the procattr without going through another dup2,
+ * which means by the time it gets to the fastcgi process it
+ * is no longer fd 0, so it doesn't work. Sigh. */
+
+ execl(command, command, NULL);
+
+ } else if (rv == APR_INPARENT) {
+ if (num_to_start == 0) {
+ apr_socket_close(skt);
+ }
+ } else {
+ exit_error(rv, "apr_proc_fork");
+ }
+ }
+
+#endif
+
+ return EXIT_SUCCESS;
+}
diff --git a/support/fcgistarter.dep b/support/fcgistarter.dep
new file mode 100644
index 0000000..d27b8d2
--- /dev/null
+++ b/support/fcgistarter.dep
@@ -0,0 +1,29 @@
+# Microsoft Developer Studio Generated Dependency File, included by fcgistarter.mak
+
+.\fcgistarter.c : \
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_dso.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_global_mutex.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_network_io.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_portable.h"\
+ "..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\srclib\apr\include\apr_shm.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_thread_proc.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
diff --git a/support/fcgistarter.dsp b/support/fcgistarter.dsp
new file mode 100644
index 0000000..9cd5780
--- /dev/null
+++ b/support/fcgistarter.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="fcgistarter" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=fcgistarter - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "fcgistarter.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "fcgistarter.mak" CFG="fcgistarter - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "fcgistarter - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "fcgistarter - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "fcgistarter - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/fcgistarter_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\fcgistarter.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/fcgistarter_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\fcgistarter.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "fcgistarter - Win32 Release"
+# Name "fcgistarter - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\fcgistarter.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/fcgistarter.mak b/support/fcgistarter.mak
new file mode 100644
index 0000000..b47d185
--- /dev/null
+++ b/support/fcgistarter.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on fcgistarter.dsp
+!IF "$(CFG)" == ""
+CFG=fcgistarter - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to fcgistarter - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "fcgistarter - Win32 Release" && "$(CFG)" != "fcgistarter - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "fcgistarter.mak" CFG="fcgistarter - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "fcgistarter - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "fcgistarter - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "fcgistarter - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\fcgistarter.obj"
+ -@erase "$(INTDIR)\fcgistarter.res"
+ -@erase "$(INTDIR)\fcgistarter_src.idb"
+ -@erase "$(INTDIR)\fcgistarter_src.pdb"
+ -@erase "$(OUTDIR)\fcgistarter.exe"
+ -@erase "$(OUTDIR)\fcgistarter.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\fcgistarter_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\fcgistarter.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\fcgistarter.pdb" /debug /out:"$(OUTDIR)\fcgistarter.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\fcgistarter.obj" \
+ "$(INTDIR)\fcgistarter.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\fcgistarter.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\fcgistarter.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\fcgistarter.exe"
+ if exist .\Release\fcgistarter.exe.manifest mt.exe -manifest .\Release\fcgistarter.exe.manifest -outputresource:.\Release\fcgistarter.exe;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\fcgistarter.obj"
+ -@erase "$(INTDIR)\fcgistarter.res"
+ -@erase "$(INTDIR)\fcgistarter_src.idb"
+ -@erase "$(INTDIR)\fcgistarter_src.pdb"
+ -@erase "$(OUTDIR)\fcgistarter.exe"
+ -@erase "$(OUTDIR)\fcgistarter.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\fcgistarter_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\fcgistarter.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\fcgistarter.pdb" /debug /out:"$(OUTDIR)\fcgistarter.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\fcgistarter.obj" \
+ "$(INTDIR)\fcgistarter.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\fcgistarter.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\fcgistarter.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\fcgistarter.exe"
+ if exist .\Debug\fcgistarter.exe.manifest mt.exe -manifest .\Debug\fcgistarter.exe.manifest -outputresource:.\Debug\fcgistarter.exe;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("fcgistarter.dep")
+!INCLUDE "fcgistarter.dep"
+!ELSE
+!MESSAGE Warning: cannot find "fcgistarter.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "fcgistarter - Win32 Release" || "$(CFG)" == "fcgistarter - Win32 Debug"
+
+!IF "$(CFG)" == "fcgistarter - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "fcgistarter - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\fcgistarter.c
+
+"$(INTDIR)\fcgistarter.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "fcgistarter - Win32 Release"
+
+
+"$(INTDIR)\fcgistarter.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug"
+
+
+"$(INTDIR)\fcgistarter.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" $(SOURCE)
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/support/htcacheclean.c b/support/htcacheclean.c
new file mode 100644
index 0000000..b4eabbf
--- /dev/null
+++ b/support/htcacheclean.c
@@ -0,0 +1,1842 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * htcacheclean.c: simple program for cleaning of
+ * the disk cache of the Apache HTTP server
+ *
+ * Contributed by Andreas Steinmetz <ast domdv.de>
+ * 8 Oct 2004
+ */
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_file_io.h"
+#include "apr_file_info.h"
+#include "apr_pools.h"
+#include "apr_hash.h"
+#include "apr_thread_proc.h"
+#include "apr_signal.h"
+#include "apr_getopt.h"
+#include "apr_md5.h"
+#include "apr_ring.h"
+#include "apr_date.h"
+#include "apr_buckets.h"
+
+#include "../modules/cache/cache_common.h"
+#include "../modules/cache/cache_disk_common.h"
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* define the following for debugging */
+#undef DEBUG
+
+/*
+ * Note: on Linux delays <= 2ms are busy waits without
+ * scheduling, so never use a delay <= 2ms below
+ */
+
+#define NICE_DELAY 10000 /* usecs */
+#define DELETE_NICE 10 /* be nice after this amount of delete ops */
+#define STAT_ATTEMPTS 10 /* maximum stat attempts for a file */
+#define STAT_DELAY 5000 /* usecs */
+#define HEADER 1 /* headers file */
+#define DATA 2 /* body file */
+#define TEMP 4 /* temporary file */
+#define HEADERDATA (HEADER|DATA)
+#define MAXDEVIATION 3600 /* secs */
+#define SECS_PER_MIN 60
+#define KBYTE 1024
+#define MBYTE 1048576
+#define GBYTE 1073741824
+
+#define DIRINFO (APR_FINFO_MTIME|APR_FINFO_SIZE|APR_FINFO_TYPE|APR_FINFO_LINK)
+
+typedef struct _direntry {
+ APR_RING_ENTRY(_direntry) link;
+ int type; /* type of file/fileset: TEMP, HEADER, DATA, HEADERDATA */
+ apr_time_t htime; /* headers file modification time */
+ apr_time_t dtime; /* body file modification time */
+ apr_off_t hsize; /* headers file size */
+ apr_off_t dsize; /* body or temporary file size */
+ char *basename; /* file/fileset base name */
+} DIRENTRY;
+
+typedef struct _entry {
+ APR_RING_ENTRY(_entry) link;
+ apr_time_t expire; /* cache entry exiration time */
+ apr_time_t response_time; /* cache entry time of last response to client */
+ apr_time_t htime; /* headers file modification time */
+ apr_time_t dtime; /* body file modification time */
+ apr_off_t hsize; /* headers file size */
+ apr_off_t dsize; /* body or temporary file size */
+ char *basename; /* fileset base name */
+} ENTRY;
+
+
+static int delcount; /* file deletion count for nice mode */
+static int interrupted; /* flag: true if SIGINT or SIGTERM occurred */
+static int realclean; /* flag: true means user said apache is not running */
+static int verbose; /* flag: true means print statistics */
+static int benice; /* flag: true means nice mode is activated */
+static int dryrun; /* flag: true means dry run, don't actually delete
+ anything */
+static int deldirs; /* flag: true means directories should be deleted */
+static int listurls; /* flag: true means list cached urls */
+static int listextended;/* flag: true means list cached urls */
+static int baselen; /* string length of the path to the proxy directory */
+static apr_time_t now; /* start time of this processing run */
+
+static apr_file_t *errfile; /* stderr file handle */
+static apr_file_t *outfile; /* stdout file handle */
+static apr_off_t unsolicited; /* file size summary for deleted unsolicited
+ files */
+static ENTRY root; /* ENTRY ring anchor */
+
+/* short program name as called */
+static const char *shortname = "htcacheclean";
+
+/* what did we clean? */
+struct stats {
+ apr_off_t total;
+ apr_off_t sum;
+ apr_off_t max;
+ apr_off_t ntotal;
+ apr_off_t nodes;
+ apr_off_t inodes;
+ apr_off_t etotal;
+ apr_off_t entries;
+ apr_off_t dfuture;
+ apr_off_t dexpired;
+ apr_off_t dfresh;
+};
+
+
+#ifdef DEBUG
+/*
+ * fake delete for debug purposes
+ */
+#define apr_file_remove fake_file_remove
+static void fake_file_remove(char *pathname, apr_pool_t *p)
+{
+ apr_finfo_t info;
+
+ /* stat and printing to simulate some deletion system load and to
+ display what would actually have happened */
+ apr_stat(&info, pathname, DIRINFO, p);
+ apr_file_printf(errfile, "would delete %s" APR_EOL_STR, pathname);
+}
+#endif
+
+/*
+ * called on SIGINT or SIGTERM
+ */
+static void setterm(int unused)
+{
+#ifdef DEBUG
+ apr_file_printf(errfile, "interrupt" APR_EOL_STR);
+#endif
+ interrupted = 1;
+}
+
+/*
+ * called in out of memory condition
+ */
+static int oom(int unused)
+{
+ static int called = 0;
+
+ /* be careful to call exit() only once */
+ if (!called) {
+ called = 1;
+ exit(1);
+ }
+ return APR_ENOMEM;
+}
+
+/*
+ * print purge statistics
+ */
+static void printstats(char *path, struct stats *s)
+{
+ char ttype, stype, mtype, utype;
+ apr_off_t tfrag, sfrag, ufrag;
+
+ if (!verbose) {
+ return;
+ }
+
+ ttype = 'K';
+ tfrag = ((s->total * 10) / KBYTE) % 10;
+ s->total /= KBYTE;
+ if (s->total >= KBYTE) {
+ ttype = 'M';
+ tfrag = ((s->total * 10) / KBYTE) % 10;
+ s->total /= KBYTE;
+ }
+
+ stype = 'K';
+ sfrag = ((s->sum * 10) / KBYTE) % 10;
+ s->sum /= KBYTE;
+ if (s->sum >= KBYTE) {
+ stype = 'M';
+ sfrag = ((s->sum * 10) / KBYTE) % 10;
+ s->sum /= KBYTE;
+ }
+
+ mtype = 'K';
+ s->max /= KBYTE;
+ if (s->max >= KBYTE) {
+ mtype = 'M';
+ s->max /= KBYTE;
+ }
+
+ apr_file_printf(errfile, "Cleaned %s. Statistics:" APR_EOL_STR, path);
+ if (unsolicited) {
+ utype = 'K';
+ ufrag = ((unsolicited * 10) / KBYTE) % 10;
+ unsolicited /= KBYTE;
+ if (unsolicited >= KBYTE) {
+ utype = 'M';
+ ufrag = ((unsolicited * 10) / KBYTE) % 10;
+ unsolicited /= KBYTE;
+ }
+ if (!unsolicited && !ufrag) {
+ ufrag = 1;
+ }
+ apr_file_printf(errfile, "unsolicited size %d.%d%c" APR_EOL_STR,
+ (int)(unsolicited), (int)(ufrag), utype);
+ }
+ apr_file_printf(errfile, "size limit %" APR_OFF_T_FMT ".0%c" APR_EOL_STR,
+ s->max, mtype);
+ apr_file_printf(errfile, "inodes limit %" APR_OFF_T_FMT APR_EOL_STR,
+ s->inodes);
+ apr_file_printf(
+ errfile,
+ "total size was %" APR_OFF_T_FMT ".%" APR_OFF_T_FMT "%c, total size now "
+ "%" APR_OFF_T_FMT ".%" APR_OFF_T_FMT "%c" APR_EOL_STR, s->total,
+ tfrag, ttype, s->sum, sfrag, stype);
+ apr_file_printf(errfile, "total inodes was %" APR_OFF_T_FMT
+ ", total %sinodes now "
+ "%" APR_OFF_T_FMT APR_EOL_STR, s->ntotal, dryrun && deldirs ? "estimated "
+ : "", s->nodes);
+ apr_file_printf(
+ errfile,
+ "total entries was %" APR_OFF_T_FMT ", total entries now %" APR_OFF_T_FMT
+ APR_EOL_STR, s->etotal, s->entries);
+ apr_file_printf(
+ errfile,
+ "%" APR_OFF_T_FMT " entries deleted (%" APR_OFF_T_FMT " from future, %"
+ APR_OFF_T_FMT " expired, %" APR_OFF_T_FMT " fresh)" APR_EOL_STR,
+ (s->etotal - s->entries), s->dfuture, s->dexpired, s->dfresh);
+}
+
+/**
+ * Round the value up to the given threshold.
+ */
+static apr_size_t round_up(apr_size_t val, apr_off_t round)
+{
+ if (round > 1) {
+ return (apr_size_t)(((val + round - 1) / round) * round);
+ }
+ return val;
+}
+
+/*
+ * delete parent directories
+ */
+static void delete_parent(const char *path, const char *basename,
+ apr_off_t *nodes, apr_pool_t *pool)
+{
+ char *nextpath, *name;
+ apr_pool_t *p;
+
+ /* temp pool, otherwise lots of memory could be allocated */
+ apr_pool_create(&p, pool);
+ name = apr_pstrdup(p, basename);
+
+ /* If asked to delete dirs, do so now. We don't care if it fails.
+ * If it fails, it likely means there was something else there.
+ */
+ if (deldirs && !dryrun) {
+ const char *vary;
+ char *end = strrchr(name, '/');
+ while (end) {
+ *end = 0;
+
+ /* remove the directory */
+ nextpath = apr_pstrcat(p, path, "/", name, NULL);
+ if (!apr_dir_remove(nextpath, p)) {
+ (*nodes)--;
+
+ /* vary directory found? */
+ vary = strstr(name, CACHE_VDIR_SUFFIX);
+ if (vary && !vary[sizeof(CACHE_VDIR_SUFFIX) - 1]) {
+ nextpath = apr_pstrcat(p, path, "/", apr_pstrndup(p, name, vary
+ - name), NULL);
+ if (!apr_file_remove(nextpath, p)) {
+ (*nodes)--;
+ }
+ }
+
+ }
+ else {
+ break;
+ }
+ end = strrchr(name, '/');
+ }
+ }
+
+ apr_pool_destroy(p);
+
+ if (benice) {
+ if (++delcount >= DELETE_NICE) {
+ apr_sleep(NICE_DELAY);
+ delcount = 0;
+ }
+ }
+
+}
+
+/*
+ * delete a single file
+ */
+static void delete_file(char *path, char *basename, apr_off_t *nodes,
+ apr_pool_t *pool)
+{
+ char *nextpath;
+ apr_pool_t *p;
+
+ /* temp pool, otherwise lots of memory could be allocated */
+ apr_pool_create(&p, pool);
+ nextpath = apr_pstrcat(p, path, "/", basename, NULL);
+
+ if (dryrun) {
+ apr_finfo_t finfo;
+ if (!apr_stat(&finfo, nextpath, APR_FINFO_NLINK, p)) {
+ (*nodes)--;
+ }
+ }
+ else if (!apr_file_remove(nextpath, p)) {
+ (*nodes)--;
+ }
+
+ apr_pool_destroy(p);
+
+ if (benice) {
+ if (++delcount >= DELETE_NICE) {
+ apr_sleep(NICE_DELAY);
+ delcount = 0;
+ }
+ }
+
+ delete_parent(path, basename, nodes, pool);
+
+}
+
+/*
+ * delete cache file set
+ */
+static void delete_entry(char *path, char *basename, apr_off_t *nodes,
+ apr_pool_t *pool)
+{
+ char *nextpath;
+ apr_pool_t *p;
+
+ /* temp pool, otherwise lots of memory could be allocated */
+ apr_pool_create(&p, pool);
+
+ nextpath = apr_pstrcat(p, path, "/", basename, CACHE_HEADER_SUFFIX, NULL);
+ if (dryrun) {
+ apr_finfo_t finfo;
+ if (!apr_stat(&finfo, nextpath, APR_FINFO_NLINK, p)) {
+ (*nodes)--;
+ }
+ }
+ else if (!apr_file_remove(nextpath, p)) {
+ (*nodes)--;
+ }
+
+ nextpath = apr_pstrcat(p, path, "/", basename, CACHE_DATA_SUFFIX, NULL);
+ if (dryrun) {
+ apr_finfo_t finfo;
+ if (!apr_stat(&finfo, nextpath, APR_FINFO_NLINK, p)) {
+ (*nodes)--;
+ }
+ }
+ else if (!apr_file_remove(nextpath, p)) {
+ (*nodes)--;
+ }
+
+ apr_pool_destroy(p);
+
+ if (benice) {
+ delcount += 2;
+ if (delcount >= DELETE_NICE) {
+ apr_sleep(NICE_DELAY);
+ delcount = 0;
+ }
+ }
+
+ delete_parent(path, basename, nodes, pool);
+
+}
+
+/*
+ * list the cache directory tree
+ */
+static int list_urls(char *path, apr_pool_t *pool, apr_off_t round)
+{
+ apr_dir_t *dir;
+ apr_finfo_t info;
+ apr_size_t len;
+ apr_pool_t *p;
+ apr_file_t *fd;
+ const char *ext, *nextpath;
+ char *url;
+ apr_uint32_t format;
+ disk_cache_info_t disk_info;
+
+ apr_pool_create(&p, pool);
+
+ if (apr_dir_open(&dir, path, p) != APR_SUCCESS) {
+ return 1;
+ }
+
+ while (apr_dir_read(&info, APR_FINFO_TYPE, dir) == APR_SUCCESS && !interrupted) {
+
+ if (info.filetype == APR_DIR) {
+ if (!strcmp(info.name, ".") || !strcmp(info.name, "..")) {
+ continue;
+ }
+
+ if (list_urls(apr_pstrcat(p, path, "/", info.name, NULL), pool, round)) {
+ return 1;
+ }
+ }
+
+ else if (info.filetype == APR_REG) {
+
+ ext = strchr(info.name, '.');
+
+ if (ext && !strcasecmp(ext, CACHE_HEADER_SUFFIX)) {
+
+ nextpath = apr_pstrcat(p, path, "/", info.name, NULL);
+
+ if (apr_file_open(&fd, nextpath, APR_FOPEN_READ
+ | APR_FOPEN_BINARY, APR_OS_DEFAULT, p) == APR_SUCCESS) {
+ len = sizeof(format);
+ if (apr_file_read_full(fd, &format, len, &len)
+ == APR_SUCCESS) {
+ if (format == DISK_FORMAT_VERSION) {
+ apr_off_t offset = 0;
+
+ apr_file_seek(fd, APR_SET, &offset);
+
+ len = sizeof(disk_cache_info_t);
+
+ if (apr_file_read_full(fd, &disk_info, len, &len)
+ == APR_SUCCESS) {
+ len = disk_info.name_len;
+ url = apr_palloc(p, len + 1);
+ url[len] = 0;
+
+ if (apr_file_read_full(fd, url, len, &len)
+ == APR_SUCCESS) {
+
+ if (listextended) {
+ apr_finfo_t hinfo, dinfo;
+
+ /* stat the header file */
+ if (APR_SUCCESS != apr_file_info_get(
+ &hinfo, APR_FINFO_SIZE, fd)) {
+ /* ignore the file */
+ }
+ else if (disk_info.has_body && APR_SUCCESS
+ != apr_stat(
+ &dinfo,
+ apr_pstrcat(
+ p,
+ path,
+ "/",
+ apr_pstrndup(
+ p,
+ info.name,
+ ext
+ - info.name),
+ CACHE_DATA_SUFFIX,
+ NULL),
+ APR_FINFO_SIZE
+ | APR_FINFO_IDENT,
+ p)) {
+ /* ignore the file */
+ }
+ else if (disk_info.has_body && (dinfo.device
+ != disk_info.device
+ || dinfo.inode
+ != disk_info.inode)) {
+ /* ignore the file */
+ }
+ else {
+
+ apr_file_printf(
+ outfile,
+ "%s %" APR_SIZE_T_FMT
+ " %" APR_SIZE_T_FMT
+ " %d %" APR_SIZE_T_FMT
+ " %" APR_TIME_T_FMT
+ " %" APR_TIME_T_FMT
+ " %" APR_TIME_T_FMT
+ " %" APR_TIME_T_FMT
+ " %d %d\n",
+ url,
+ round_up((apr_size_t)hinfo.size, round),
+ round_up(
+ disk_info.has_body ? (apr_size_t)dinfo.size
+ : 0, round),
+ disk_info.status,
+ disk_info.entity_version,
+ disk_info.date,
+ disk_info.expire,
+ disk_info.request_time,
+ disk_info.response_time,
+ disk_info.has_body,
+ disk_info.header_only);
+ }
+ }
+ else {
+ apr_finfo_t dinfo;
+
+ /* stat the data file */
+ if (disk_info.has_body && APR_SUCCESS
+ != apr_stat(
+ &dinfo,
+ apr_pstrcat(
+ p,
+ path,
+ "/",
+ apr_pstrndup(
+ p,
+ info.name,
+ ext
+ - info.name),
+ CACHE_DATA_SUFFIX,
+ NULL),
+ APR_FINFO_SIZE
+ | APR_FINFO_IDENT,
+ p)) {
+ /* ignore the file */
+ }
+ else if (disk_info.has_body && (dinfo.device
+ != disk_info.device
+ || dinfo.inode
+ != disk_info.inode)) {
+ /* ignore the file */
+ }
+ else {
+ apr_file_printf(outfile, "%s\n",
+ url);
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ apr_file_close(fd);
+
+ }
+ }
+ }
+
+ }
+
+ apr_dir_close(dir);
+
+ if (interrupted) {
+ return 1;
+ }
+
+ apr_pool_destroy(p);
+
+ if (benice) {
+ apr_sleep(NICE_DELAY);
+ }
+
+ if (interrupted) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * walk the cache directory tree
+ */
+static int process_dir(char *path, apr_pool_t *pool, apr_off_t *nodes)
+{
+ apr_dir_t *dir;
+ apr_pool_t *p;
+ apr_hash_t *h;
+ apr_hash_index_t *i;
+ apr_file_t *fd;
+ apr_status_t status;
+ apr_finfo_t info;
+ apr_size_t len;
+ apr_time_t current, deviation;
+ char *nextpath, *base, *ext;
+ DIRENTRY *d, *t, *n, anchor;
+ ENTRY *e;
+ int skip, retries;
+ disk_cache_info_t disk_info;
+
+ APR_RING_INIT(&anchor.link, _direntry, link);
+ apr_pool_create(&p, pool);
+ h = apr_hash_make(p);
+ fd = NULL;
+ deviation = MAXDEVIATION * APR_USEC_PER_SEC;
+
+ if (apr_dir_open(&dir, path, p) != APR_SUCCESS) {
+ return 1;
+ }
+
+ while (apr_dir_read(&info, 0, dir) == APR_SUCCESS && !interrupted) {
+ if (!strcmp(info.name, ".") || !strcmp(info.name, "..")) {
+ continue;
+ }
+ d = apr_pcalloc(p, sizeof(DIRENTRY));
+ d->basename = apr_pstrcat(p, path, "/", info.name, NULL);
+ APR_RING_INSERT_TAIL(&anchor.link, d, _direntry, link);
+ (*nodes)++;
+ }
+
+ apr_dir_close(dir);
+
+ if (interrupted) {
+ return 1;
+ }
+
+ skip = baselen + 1;
+
+ for (d = APR_RING_FIRST(&anchor.link);
+ !interrupted && d != APR_RING_SENTINEL(&anchor.link, _direntry, link);
+ d=n) {
+ n = APR_RING_NEXT(d, link);
+ base = strrchr(d->basename, '/');
+ if (!base++) {
+ base = d->basename;
+ }
+ ext = strchr(base, '.');
+
+ /* there may be temporary files which may be gone before
+ * processing, always skip these if not in realclean mode
+ */
+ if (!ext && !realclean) {
+ if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN)
+ && strlen(base) == AP_TEMPFILE_NAMELEN) {
+ continue;
+ }
+ }
+
+ /* this may look strange but apr_stat() may return an error which
+ * is system dependent and there may be transient failures,
+ * so just blindly retry for a short while
+ */
+ retries = STAT_ATTEMPTS;
+ status = APR_SUCCESS;
+ do {
+ if (status != APR_SUCCESS) {
+ apr_sleep(STAT_DELAY);
+ }
+ status = apr_stat(&info, d->basename, DIRINFO, p);
+ } while (status != APR_SUCCESS && !interrupted && --retries);
+
+ /* what may happen here is that apache did create a file which
+ * we did detect but then does delete the file before we can
+ * get file information, so if we don't get any file information
+ * we will ignore the file in this case
+ */
+ if (status != APR_SUCCESS) {
+ if (!realclean && !interrupted) {
+ continue;
+ }
+ return 1;
+ }
+
+ if (info.filetype == APR_DIR) {
+ char *dirpath = apr_pstrdup(p, d->basename);
+
+ if (process_dir(d->basename, pool, nodes)) {
+ return 1;
+ }
+ /* When given the -t option htcacheclean does not
+ * delete directories that are already empty, so we'll do that here
+ * since process_dir checks all the directories.
+ * If it fails, it likely means there was something else there.
+ */
+ if (deldirs && !dryrun) {
+ apr_dir_remove(dirpath, p);
+ }
+ continue;
+ }
+
+ if (info.filetype != APR_REG) {
+ continue;
+ }
+
+ if (!ext) {
+ if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN)
+ && strlen(base) == AP_TEMPFILE_NAMELEN) {
+ d->basename += skip;
+ d->type = TEMP;
+ d->dsize = info.size;
+ apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
+ }
+ continue;
+ }
+
+ if (!strcasecmp(ext, CACHE_HEADER_SUFFIX)) {
+ *ext = '\0';
+ d->basename += skip;
+ /* if a user manually creates a '.header' file */
+ if (d->basename[0] == '\0') {
+ continue;
+ }
+ t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING);
+ if (t) {
+ d = t;
+ }
+ d->type |= HEADER;
+ d->htime = info.mtime;
+ d->hsize = info.size;
+ apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
+ continue;
+ }
+
+ if (!strcasecmp(ext, CACHE_DATA_SUFFIX)) {
+ *ext = '\0';
+ d->basename += skip;
+ /* if a user manually creates a '.data' file */
+ if (d->basename[0] == '\0') {
+ continue;
+ }
+ t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING);
+ if (t) {
+ d = t;
+ }
+ d->type |= DATA;
+ d->dtime = info.mtime;
+ d->dsize = info.size;
+ apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
+ }
+ }
+
+ if (interrupted) {
+ return 1;
+ }
+
+ path[baselen] = '\0';
+
+ for (i = apr_hash_first(p, h); i && !interrupted; i = apr_hash_next(i)) {
+ void *hvalue;
+ apr_uint32_t format;
+
+ apr_hash_this(i, NULL, NULL, &hvalue);
+ d = hvalue;
+
+ switch(d->type) {
+ case HEADERDATA:
+ nextpath = apr_pstrcat(p, path, "/", d->basename,
+ CACHE_HEADER_SUFFIX, NULL);
+ if (apr_file_open(&fd, nextpath, APR_FOPEN_READ | APR_FOPEN_BINARY,
+ APR_OS_DEFAULT, p) == APR_SUCCESS) {
+ len = sizeof(format);
+ if (apr_file_read_full(fd, &format, len,
+ &len) == APR_SUCCESS) {
+ if (format == DISK_FORMAT_VERSION) {
+ apr_off_t offset = 0;
+
+ apr_file_seek(fd, APR_SET, &offset);
+
+ len = sizeof(disk_cache_info_t);
+
+ if (apr_file_read_full(fd, &disk_info, len,
+ &len) == APR_SUCCESS) {
+ apr_file_close(fd);
+ e = apr_palloc(pool, sizeof(ENTRY));
+ APR_RING_INSERT_TAIL(&root.link, e, _entry, link);
+ e->expire = disk_info.expire;
+ e->response_time = disk_info.response_time;
+ e->htime = d->htime;
+ e->dtime = d->dtime;
+ e->hsize = d->hsize;
+ e->dsize = d->dsize;
+ e->basename = apr_pstrdup(pool, d->basename);
+ if (!disk_info.has_body) {
+ delete_file(path, apr_pstrcat(p, path, "/",
+ d->basename, CACHE_DATA_SUFFIX, NULL),
+ nodes, p);
+ }
+ break;
+ }
+ else {
+ apr_file_close(fd);
+ }
+ }
+ else if (format == VARY_FORMAT_VERSION) {
+ apr_finfo_t finfo;
+
+ /* This must be a URL that added Vary headers later,
+ * so kill the orphaned .data file
+ */
+ apr_file_close(fd);
+
+ if (apr_stat(&finfo, apr_pstrcat(p, nextpath,
+ CACHE_VDIR_SUFFIX, NULL), APR_FINFO_TYPE, p)
+ || finfo.filetype != APR_DIR) {
+ delete_entry(path, d->basename, nodes, p);
+ }
+ else {
+ delete_file(path, apr_pstrcat(p, path, "/",
+ d->basename, CACHE_DATA_SUFFIX, NULL),
+ nodes, p);
+ }
+ break;
+ }
+ else {
+ /* We didn't recognise the format, kill the files */
+ apr_file_close(fd);
+ delete_entry(path, d->basename, nodes, p);
+ break;
+ }
+ }
+ else {
+ apr_file_close(fd);
+ }
+
+ }
+ /* we have a somehow unreadable headers file which is associated
+ * with a data file. this may be caused by apache currently
+ * rewriting the headers file. thus we may delete the file set
+ * either in realclean mode or if the headers file modification
+ * timestamp is not within a specified positive or negative offset
+ * to the current time.
+ */
+ current = apr_time_now();
+ if (realclean || d->htime < current - deviation
+ || d->htime > current + deviation) {
+ delete_entry(path, d->basename, nodes, p);
+ unsolicited += d->hsize;
+ unsolicited += d->dsize;
+ }
+ break;
+
+ /* single data and header files may be deleted either in realclean
+ * mode or if their modification timestamp is not within a
+ * specified positive or negative offset to the current time.
+ * this handling is necessary due to possible race conditions
+ * between apache and this process
+ */
+ case HEADER:
+ current = apr_time_now();
+ nextpath = apr_pstrcat(p, path, "/", d->basename,
+ CACHE_HEADER_SUFFIX, NULL);
+ if (apr_file_open(&fd, nextpath, APR_FOPEN_READ | APR_FOPEN_BINARY,
+ APR_OS_DEFAULT, p) == APR_SUCCESS) {
+ len = sizeof(format);
+ if (apr_file_read_full(fd, &format, len,
+ &len) == APR_SUCCESS) {
+ if (format == VARY_FORMAT_VERSION) {
+ apr_time_t expires;
+
+ len = sizeof(expires);
+
+ if (apr_file_read_full(fd, &expires, len,
+ &len) == APR_SUCCESS) {
+ apr_finfo_t finfo;
+
+ apr_file_close(fd);
+
+ if (apr_stat(&finfo, apr_pstrcat(p, nextpath,
+ CACHE_VDIR_SUFFIX, NULL), APR_FINFO_TYPE, p)
+ || finfo.filetype != APR_DIR) {
+ delete_entry(path, d->basename, nodes, p);
+ }
+ else if (expires < current) {
+ delete_entry(path, d->basename, nodes, p);
+ }
+
+ break;
+ }
+ }
+ else if (format == DISK_FORMAT_VERSION) {
+ apr_off_t offset = 0;
+
+ apr_file_seek(fd, APR_SET, &offset);
+
+ len = sizeof(disk_cache_info_t);
+
+ if (apr_file_read_full(fd, &disk_info, len,
+ &len) == APR_SUCCESS) {
+ apr_file_close(fd);
+ e = apr_palloc(pool, sizeof(ENTRY));
+ APR_RING_INSERT_TAIL(&root.link, e, _entry, link);
+ e->expire = disk_info.expire;
+ e->response_time = disk_info.response_time;
+ e->htime = d->htime;
+ e->dtime = d->dtime;
+ e->hsize = d->hsize;
+ e->dsize = d->dsize;
+ e->basename = apr_pstrdup(pool, d->basename);
+ break;
+ }
+ else {
+ apr_file_close(fd);
+ }
+ }
+ else {
+ apr_file_close(fd);
+ delete_entry(path, d->basename, nodes, p);
+ break;
+ }
+ }
+ else {
+ apr_file_close(fd);
+ }
+ }
+
+ if (realclean || d->htime < current - deviation
+ || d->htime > current + deviation) {
+ delete_entry(path, d->basename, nodes, p);
+ unsolicited += d->hsize;
+ }
+ break;
+
+ case DATA:
+ current = apr_time_now();
+ if (realclean || d->dtime < current - deviation
+ || d->dtime > current + deviation) {
+ delete_entry(path, d->basename, nodes, p);
+ unsolicited += d->dsize;
+ }
+ break;
+
+ /* temp files may only be deleted in realclean mode which
+ * is asserted above if a tempfile is in the hash array
+ */
+ case TEMP:
+ delete_file(path, d->basename, nodes, p);
+ unsolicited += d->dsize;
+ break;
+ }
+ }
+
+ if (interrupted) {
+ return 1;
+ }
+
+ apr_pool_destroy(p);
+
+ if (benice) {
+ apr_sleep(NICE_DELAY);
+ }
+
+ if (interrupted) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * purge cache entries
+ */
+static void purge(char *path, apr_pool_t *pool, apr_off_t max,
+ apr_off_t inodes, apr_off_t nodes, apr_off_t round)
+{
+ ENTRY *e, *n, *oldest;
+
+ struct stats s;
+ s.sum = 0;
+ s.entries = 0;
+ s.dfuture = 0;
+ s.dexpired = 0;
+ s.dfresh = 0;
+ s.max = max;
+ s.nodes = nodes;
+ s.inodes = inodes;
+ s.ntotal = nodes;
+
+ for (e = APR_RING_FIRST(&root.link);
+ e != APR_RING_SENTINEL(&root.link, _entry, link);
+ e = APR_RING_NEXT(e, link)) {
+ s.sum += round_up((apr_size_t)e->hsize, round);
+ s.sum += round_up((apr_size_t)e->dsize, round);
+ s.entries++;
+ }
+
+ s.total = s.sum;
+ s.etotal = s.entries;
+
+ if ((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) {
+ printstats(path, &s);
+ return;
+ }
+
+ /* process all entries with a timestamp in the future, this may
+ * happen if a wrong system time is corrected
+ */
+
+ for (e = APR_RING_FIRST(&root.link);
+ e != APR_RING_SENTINEL(&root.link, _entry, link) && !interrupted;) {
+ n = APR_RING_NEXT(e, link);
+ if (e->response_time > now || e->htime > now || e->dtime > now) {
+ delete_entry(path, e->basename, &s.nodes, pool);
+ s.sum -= round_up((apr_size_t)e->hsize, round);
+ s.sum -= round_up((apr_size_t)e->dsize, round);
+ s.entries--;
+ s.dfuture++;
+ APR_RING_REMOVE(e, link);
+ if ((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) {
+ if (!interrupted) {
+ printstats(path, &s);
+ }
+ return;
+ }
+ }
+ e = n;
+ }
+
+ if (interrupted) {
+ return;
+ }
+
+ /* process all entries which are expired */
+ for (e = APR_RING_FIRST(&root.link);
+ e != APR_RING_SENTINEL(&root.link, _entry, link) && !interrupted;) {
+ n = APR_RING_NEXT(e, link);
+ if (e->expire != APR_DATE_BAD && e->expire < now) {
+ delete_entry(path, e->basename, &s.nodes, pool);
+ s.sum -= round_up((apr_size_t)e->hsize, round);
+ s.sum -= round_up((apr_size_t)e->dsize, round);
+ s.entries--;
+ s.dexpired++;
+ APR_RING_REMOVE(e, link);
+ if ((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) {
+ if (!interrupted) {
+ printstats(path, &s);
+ }
+ return;
+ }
+ }
+ e = n;
+ }
+
+ if (interrupted) {
+ return;
+ }
+
+ /* process remaining entries oldest to newest, the check for an empty
+ * ring actually isn't necessary except when the compiler does
+ * corrupt 64bit arithmetics which happened to me once, so better safe
+ * than sorry
+ */
+ while (!((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes))
+ && !interrupted && !APR_RING_EMPTY(&root.link, _entry, link)) {
+ oldest = APR_RING_FIRST(&root.link);
+
+ for (e = APR_RING_NEXT(oldest, link);
+ e != APR_RING_SENTINEL(&root.link, _entry, link);
+ e = APR_RING_NEXT(e, link)) {
+ if (e->dtime < oldest->dtime) {
+ oldest = e;
+ }
+ }
+
+ delete_entry(path, oldest->basename, &s.nodes, pool);
+ s.sum -= round_up((apr_size_t)oldest->hsize, round);
+ s.sum -= round_up((apr_size_t)oldest->dsize, round);
+ s.entries--;
+ s.dfresh++;
+ APR_RING_REMOVE(oldest, link);
+ }
+
+ if (!interrupted) {
+ printstats(path, &s);
+ }
+}
+
+static apr_status_t remove_directory(apr_pool_t *pool, const char *dir)
+{
+ apr_status_t rv;
+ apr_dir_t *dirp;
+ apr_finfo_t dirent;
+
+ rv = apr_dir_open(&dirp, dir, pool);
+ if (APR_STATUS_IS_ENOENT(rv)) {
+ return rv;
+ }
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile, "Could not open directory %s: %pm" APR_EOL_STR,
+ dir, &rv);
+ return rv;
+ }
+
+ while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp)
+ == APR_SUCCESS) {
+ if (dirent.filetype == APR_DIR) {
+ if (strcmp(dirent.name, ".") && strcmp(dirent.name, "..")) {
+ rv = remove_directory(pool, apr_pstrcat(pool, dir, "/",
+ dirent.name, NULL));
+ /* tolerate the directory not being empty, the cache may have
+ * attempted to recreate the directory in the mean time.
+ */
+ if (APR_SUCCESS != rv && APR_ENOTEMPTY != rv) {
+ break;
+ }
+ }
+ } else {
+ const char *file = apr_pstrcat(pool, dir, "/", dirent.name, NULL);
+ rv = apr_file_remove(file, pool);
+ if (APR_SUCCESS != rv) {
+ apr_file_printf(errfile,
+ "Could not remove file '%s': %pm" APR_EOL_STR, file,
+ &rv);
+ break;
+ }
+ }
+ }
+
+ apr_dir_close(dirp);
+
+ if (rv == APR_SUCCESS) {
+ rv = apr_dir_remove(dir, pool);
+ if (APR_ENOTEMPTY == rv) {
+ rv = APR_SUCCESS;
+ }
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile, "Could not remove directory %s: %pm" APR_EOL_STR,
+ dir, &rv);
+ }
+ }
+
+ return rv;
+}
+
+static apr_status_t find_directory(apr_pool_t *pool, const char *base,
+ const char *rest)
+{
+ apr_status_t rv;
+ apr_dir_t *dirp;
+ apr_finfo_t dirent;
+ int found = 0, files = 0;
+ const char *header = apr_pstrcat(pool, rest, CACHE_HEADER_SUFFIX, NULL);
+ const char *data = apr_pstrcat(pool, rest, CACHE_DATA_SUFFIX, NULL);
+ const char *vdir = apr_pstrcat(pool, rest, CACHE_HEADER_SUFFIX,
+ CACHE_VDIR_SUFFIX, NULL);
+ const char *dirname = NULL;
+
+ rv = apr_dir_open(&dirp, base, pool);
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile, "Could not open directory %s: %pm" APR_EOL_STR,
+ base, &rv);
+ return rv;
+ }
+
+ rv = APR_ENOENT;
+
+ while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp)
+ == APR_SUCCESS) {
+ int len = strlen(dirent.name);
+ int restlen = strlen(rest);
+ if (dirent.filetype == APR_DIR && !strncmp(rest, dirent.name, len)) {
+ dirname = apr_pstrcat(pool, base, "/", dirent.name, NULL);
+ rv = find_directory(pool, dirname, rest + (len < restlen ? len
+ : restlen));
+ if (APR_SUCCESS == rv) {
+ found = 1;
+ }
+ }
+ if (dirent.filetype == APR_DIR) {
+ if (!strcmp(dirent.name, vdir)) {
+ files = 1;
+ }
+ }
+ if (dirent.filetype == APR_REG) {
+ if (!strcmp(dirent.name, header) || !strcmp(dirent.name, data)) {
+ files = 1;
+ }
+ }
+ }
+
+ apr_dir_close(dirp);
+
+ if (files) {
+ rv = APR_SUCCESS;
+ if (!dryrun) {
+ const char *remove;
+ apr_status_t status;
+
+ remove = apr_pstrcat(pool, base, "/", header, NULL);
+ status = apr_file_remove(remove, pool);
+ if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) {
+ apr_file_printf(errfile, "Could not remove file %s: %pm" APR_EOL_STR,
+ remove, &status);
+ rv = status;
+ }
+
+ remove = apr_pstrcat(pool, base, "/", data, NULL);
+ status = apr_file_remove(remove, pool);
+ if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) {
+ apr_file_printf(errfile, "Could not remove file %s: %pm" APR_EOL_STR,
+ remove, &status);
+ rv = status;
+ }
+
+ status = remove_directory(pool, apr_pstrcat(pool, base, "/", vdir, NULL));
+ if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) {
+ rv = status;
+ }
+ }
+ }
+
+ /* If asked to delete dirs, do so now. We don't care if it fails.
+ * If it fails, it likely means there was something else there.
+ */
+ if (dirname && deldirs && !dryrun) {
+ apr_dir_remove(dirname, pool);
+ }
+
+ if (found) {
+ return APR_SUCCESS;
+ }
+
+ return rv;
+}
+
+/**
+ * Delete a specific URL from the cache.
+ */
+static apr_status_t delete_url(apr_pool_t *pool, const char *proxypath, const char *url)
+{
+ apr_md5_ctx_t context;
+ unsigned char digest[16];
+ char tmp[23];
+ int i, k;
+ unsigned int x;
+ static const char enc_table[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
+
+ apr_md5_init(&context);
+ apr_md5_update(&context, (const unsigned char *) url, strlen(url));
+ apr_md5_final(digest, &context);
+
+ /* encode 128 bits as 22 characters, using a modified uuencoding
+ * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is
+ * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
+ */
+ for (i = 0, k = 0; i < 15; i += 3) {
+ x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
+ tmp[k++] = enc_table[x >> 18];
+ tmp[k++] = enc_table[(x >> 12) & 0x3f];
+ tmp[k++] = enc_table[(x >> 6) & 0x3f];
+ tmp[k++] = enc_table[x & 0x3f];
+ }
+
+ /* one byte left */
+ x = digest[15];
+ tmp[k++] = enc_table[x >> 2]; /* use up 6 bits */
+ tmp[k++] = enc_table[(x << 4) & 0x3f];
+ tmp[k] = 0;
+
+ /* automatically find the directory levels */
+ return find_directory(pool, proxypath, tmp);
+}
+
+/*
+ * usage info
+ */
+#define NL APR_EOL_STR
+static void usage(const char *error)
+{
+ if (error) {
+ apr_file_printf(errfile, "%s error: %s\n", shortname, error);
+ }
+ apr_file_printf(errfile,
+ "%s -- program for cleaning the disk cache." NL
+ "Usage: %s [-Dvtrn] -pPATH [-lLIMIT] [-LLIMIT] [-PPIDFILE]" NL
+ " %s [-nti] -dINTERVAL -pPATH [-lLIMIT] [-LLIMIT] [-PPIDFILE]" NL
+ " %s [-Dvt] -pPATH URL ..." NL
+ NL
+ "Options:" NL
+ " -d Daemonize and repeat cache cleaning every INTERVAL minutes." NL
+ " This option is mutually exclusive with the -D, -v and -r" NL
+ " options." NL
+ NL
+ " -D Do a dry run and don't delete anything. This option is mutually" NL
+ " exclusive with the -d option. When doing a dry run and deleting" NL
+ " directories with -t, the inodes reported deleted in the stats" NL
+ " cannot take into account the directories deleted, and will be" NL
+ " marked as an estimate." NL
+ NL
+ " -v Be verbose and print statistics. This option is mutually" NL
+ " exclusive with the -d option." NL
+ NL
+ " -r Clean thoroughly. This assumes that the Apache web server is " NL
+ " not running. This option is mutually exclusive with the -d" NL
+ " option and implies -t." NL
+ NL
+ " -n Be nice. This causes slower processing in favour of other" NL
+ " processes." NL
+ NL
+ " -t Delete all empty directories. By default only cache files are" NL
+ " removed, however with some configurations the large number of" NL
+ " directories created may require attention." NL
+ NL
+ " -p Specify PATH as the root directory of the disk cache." NL
+ NL
+ " -P Specify PIDFILE as the file to write the pid to." NL
+ NL
+ " -R Specify amount to round sizes up to." NL
+ NL
+ " -l Specify LIMIT as the total disk cache size limit. Attach 'K'," NL
+ " 'M' or 'G' to the number for specifying KBytes, MBytes or" NL
+ " GBytes." NL
+ NL
+ " -L Specify LIMIT as the total disk cache inode limit. 'K', 'M' or" NL
+ " 'G' suffix can also be used." NL
+ NL
+ " -i Be intelligent and run only when there was a modification of" NL
+ " the disk cache. This option is only possible together with the" NL
+ " -d option." NL
+ NL
+ " -a List the URLs currently stored in the cache. Variants of the" NL
+ " same URL will be listed once for each variant." NL
+ NL
+ " -A List the URLs currently stored in the cache, along with their" NL
+ " attributes in the following order: url, header size, body size," NL
+ " status, entity version, date, expiry, request time," NL
+ " response time, body present, head request." NL
+ NL
+ "Should an URL be provided on the command line, the URL will be" NL
+ "deleted from the cache. A reverse proxied URL is made up as follows:" NL
+ "http://<hostname>:<port><path>?[query]. So, for the path \"/\" on the" NL
+ "host \"localhost\" and port 80, the URL to delete becomes" NL
+ "\"http://localhost:80/?\". Note the '?' in the URL must always be" NL
+ "specified explicitly, whether a query string is present or not." NL,
+ shortname,
+ shortname,
+ shortname,
+ shortname
+ );
+
+ exit(1);
+}
+#undef NL
+
+static void usage_repeated_arg(apr_pool_t *pool, char option)
+{
+ usage(apr_psprintf(pool,
+ "The option '%c' cannot be specified more than once",
+ option));
+}
+
+static void log_pid(apr_pool_t *pool, const char *pidfilename, apr_file_t **pidfile)
+{
+ apr_status_t status;
+ pid_t mypid = getpid();
+
+ if (APR_SUCCESS == (status = apr_file_open(pidfile, pidfilename,
+ APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE |
+ APR_FOPEN_DELONCLOSE, APR_FPROT_UREAD | APR_FPROT_UWRITE |
+ APR_FPROT_GREAD | APR_FPROT_WREAD, pool))) {
+ apr_file_printf(*pidfile, "%" APR_PID_T_FMT APR_EOL_STR, mypid);
+ }
+ else {
+ if (errfile) {
+ apr_file_printf(errfile,
+ "Could not write the pid file '%s': %pm" APR_EOL_STR,
+ pidfilename, &status);
+ }
+ exit(1);
+ }
+}
+
+/*
+ * main
+ */
+int main(int argc, const char * const argv[])
+{
+ apr_off_t max, inodes, round;
+ apr_time_t current, repeat, delay, previous;
+ apr_status_t status;
+ apr_pool_t *pool, *instance;
+ apr_getopt_t *o;
+ apr_finfo_t info;
+ apr_file_t *pidfile;
+ int retries, isdaemon, limit_found, inodes_found, intelligent, dowork;
+ char opt;
+ const char *arg;
+ char *proxypath, *path, *pidfilename;
+
+ interrupted = 0;
+ repeat = 0;
+ isdaemon = 0;
+ dryrun = 0;
+ limit_found = 0;
+ inodes_found = 0;
+ max = 0;
+ inodes = 0;
+ round = 0;
+ verbose = 0;
+ realclean = 0;
+ benice = 0;
+ deldirs = 0;
+ intelligent = 0;
+ previous = 0; /* avoid compiler warning */
+ proxypath = NULL;
+ pidfilename = NULL;
+
+ if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) {
+ return 1;
+ }
+ atexit(apr_terminate);
+
+ if (argc) {
+ shortname = apr_filepath_name_get(argv[0]);
+ }
+
+ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+ return 1;
+ }
+ apr_pool_abort_set(oom, pool);
+ apr_file_open_stderr(&errfile, pool);
+ apr_file_open_stdout(&outfile, pool);
+ apr_signal(SIGINT, setterm);
+ apr_signal(SIGTERM, setterm);
+
+ apr_getopt_init(&o, pool, argc, argv);
+
+ while (1) {
+ status = apr_getopt(o, "iDnvrtd:l:L:p:P:R:aA", &opt, &arg);
+ if (status == APR_EOF) {
+ break;
+ }
+ else if (status != APR_SUCCESS) {
+ usage(NULL);
+ }
+ else {
+ char *end;
+ apr_status_t rv;
+ switch (opt) {
+ case 'i':
+ if (intelligent) {
+ usage_repeated_arg(pool, opt);
+ }
+ intelligent = 1;
+ break;
+
+ case 'D':
+ if (dryrun) {
+ usage_repeated_arg(pool, opt);
+ }
+ dryrun = 1;
+ break;
+
+ case 'n':
+ if (benice) {
+ usage_repeated_arg(pool, opt);
+ }
+ benice = 1;
+ break;
+
+ case 't':
+ if (deldirs) {
+ usage_repeated_arg(pool, opt);
+ }
+ deldirs = 1;
+ break;
+
+ case 'v':
+ if (verbose) {
+ usage_repeated_arg(pool, opt);
+ }
+ verbose = 1;
+ break;
+
+ case 'r':
+ if (realclean) {
+ usage_repeated_arg(pool, opt);
+ }
+ realclean = 1;
+ deldirs = 1;
+ break;
+
+ case 'd':
+ if (isdaemon) {
+ usage_repeated_arg(pool, opt);
+ }
+ isdaemon = 1;
+ repeat = apr_atoi64(arg);
+ repeat *= SECS_PER_MIN;
+ repeat *= APR_USEC_PER_SEC;
+ break;
+
+ case 'l':
+ if (limit_found) {
+ usage_repeated_arg(pool, opt);
+ }
+ limit_found = 1;
+
+ do {
+ rv = apr_strtoff(&max, arg, &end, 10);
+ if (rv == APR_SUCCESS) {
+ if ((*end == 'K' || *end == 'k') && !end[1]) {
+ max *= KBYTE;
+ }
+ else if ((*end == 'M' || *end == 'm') && !end[1]) {
+ max *= MBYTE;
+ }
+ else if ((*end == 'G' || *end == 'g') && !end[1]) {
+ max *= GBYTE;
+ }
+ else if (*end && /* neither empty nor [Bb] */
+ ((*end != 'B' && *end != 'b') || end[1])) {
+ rv = APR_EGENERAL;
+ }
+ }
+ if (rv != APR_SUCCESS) {
+ usage(apr_psprintf(pool, "Invalid limit: %s"
+ APR_EOL_STR APR_EOL_STR, arg));
+ }
+ } while (0);
+ break;
+
+ case 'L':
+ if (inodes_found) {
+ usage_repeated_arg(pool, opt);
+ }
+ inodes_found = 1;
+
+ do {
+ rv = apr_strtoff(&inodes, arg, &end, 10);
+ if (rv == APR_SUCCESS) {
+ if ((*end == 'K' || *end == 'k') && !end[1]) {
+ inodes *= KBYTE;
+ }
+ else if ((*end == 'M' || *end == 'm') && !end[1]) {
+ inodes *= MBYTE;
+ }
+ else if ((*end == 'G' || *end == 'g') && !end[1]) {
+ inodes *= GBYTE;
+ }
+ else if (*end && /* neither empty nor [Bb] */
+ ((*end != 'B' && *end != 'b') || end[1])) {
+ rv = APR_EGENERAL;
+ }
+ }
+ if (rv != APR_SUCCESS) {
+ usage(apr_psprintf(pool, "Invalid limit: %s"
+ APR_EOL_STR APR_EOL_STR, arg));
+ }
+ } while (0);
+ break;
+
+ case 'a':
+ if (listurls) {
+ usage_repeated_arg(pool, opt);
+ }
+ listurls = 1;
+ break;
+
+ case 'A':
+ if (listurls) {
+ usage_repeated_arg(pool, opt);
+ }
+ listurls = 1;
+ listextended = 1;
+ break;
+
+ case 'p':
+ if (proxypath) {
+ usage_repeated_arg(pool, opt);
+ }
+ proxypath = apr_pstrdup(pool, arg);
+ if ((status = apr_filepath_set(proxypath, pool)) != APR_SUCCESS) {
+ usage(apr_psprintf(pool, "Could not set filepath to '%s': %pm",
+ proxypath, &status));
+ }
+ break;
+
+ case 'P':
+ if (pidfilename) {
+ usage_repeated_arg(pool, opt);
+ }
+ pidfilename = apr_pstrdup(pool, arg);
+ break;
+
+ case 'R':
+ if (round) {
+ usage_repeated_arg(pool, opt);
+ }
+ rv = apr_strtoff(&round, arg, &end, 10);
+ if (rv == APR_SUCCESS) {
+ if (*end) {
+ usage(apr_psprintf(pool, "Invalid round value: %s"
+ APR_EOL_STR APR_EOL_STR, arg));
+ }
+ else if (round < 0) {
+ usage(apr_psprintf(pool, "Round value must be positive: %s"
+ APR_EOL_STR APR_EOL_STR, arg));
+ }
+ }
+ if (rv != APR_SUCCESS) {
+ usage(apr_psprintf(pool, "Invalid round value: %s"
+ APR_EOL_STR APR_EOL_STR, arg));
+ }
+ break;
+
+ } /* switch */
+ } /* else */
+ } /* while */
+
+ if (argc <= 1) {
+ usage(NULL);
+ }
+
+ if (!proxypath) {
+ usage("Option -p must be specified");
+ }
+
+ if (o->ind < argc) {
+ int deleted = 0;
+ int error = 0;
+ if (isdaemon) {
+ usage("Option -d cannot be used with URL arguments, aborting");
+ }
+ if (intelligent) {
+ usage("Option -i cannot be used with URL arguments, aborting");
+ }
+ if (limit_found) {
+ usage("Option -l and -L cannot be used with URL arguments, aborting");
+ }
+ while (o->ind < argc) {
+ status = delete_url(pool, proxypath, argv[o->ind]);
+ if (APR_SUCCESS == status) {
+ if (verbose) {
+ apr_file_printf(errfile, "Removed: %s" APR_EOL_STR,
+ argv[o->ind]);
+ }
+ deleted = 1;
+ }
+ else if (APR_ENOENT == status) {
+ if (verbose) {
+ apr_file_printf(errfile, "Not cached: %s" APR_EOL_STR,
+ argv[o->ind]);
+ }
+ }
+ else {
+ if (verbose) {
+ apr_file_printf(errfile, "Error while removed: %s" APR_EOL_STR,
+ argv[o->ind]);
+ }
+ error = 1;
+ }
+ o->ind++;
+ }
+ return error ? 1 : deleted ? 0 : 2;
+ }
+
+ if (isdaemon && repeat <= 0) {
+ usage("Option -d must be greater than zero");
+ }
+
+ if (isdaemon && (verbose || realclean || dryrun || listurls)) {
+ usage("Option -d cannot be used with -v, -r, -L or -D");
+ }
+
+ if (!isdaemon && intelligent) {
+ usage("Option -i cannot be used without -d");
+ }
+
+ if (!listurls && max <= 0 && inodes <= 0) {
+ usage("At least one of option -l or -L must be greater than zero");
+ }
+
+ if (apr_filepath_get(&path, 0, pool) != APR_SUCCESS) {
+ usage(apr_psprintf(pool, "Could not get the filepath: %pm", &status));
+ }
+ baselen = strlen(path);
+
+ if (pidfilename) {
+ log_pid(pool, pidfilename, &pidfile); /* before daemonizing, so we
+ * can report errors
+ */
+ }
+
+ if (listurls) {
+ list_urls(path, pool, round);
+ return (interrupted != 0);
+ }
+
+#ifndef DEBUG
+ if (isdaemon) {
+ apr_file_close(errfile);
+ errfile = NULL;
+ if (pidfilename) {
+ apr_file_close(pidfile); /* delete original pidfile only in parent */
+ }
+ apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
+ if (pidfilename) {
+ log_pid(pool, pidfilename, &pidfile);
+ }
+ }
+#endif
+
+ do {
+ apr_pool_create(&instance, pool);
+
+ now = apr_time_now();
+ APR_RING_INIT(&root.link, _entry, link);
+ delcount = 0;
+ unsolicited = 0;
+ dowork = 0;
+
+ switch (intelligent) {
+ case 0:
+ dowork = 1;
+ break;
+
+ case 1:
+ retries = STAT_ATTEMPTS;
+ status = APR_SUCCESS;
+
+ do {
+ if (status != APR_SUCCESS) {
+ apr_sleep(STAT_DELAY);
+ }
+ status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
+ } while (status != APR_SUCCESS && !interrupted && --retries);
+
+ if (status == APR_SUCCESS) {
+ previous = info.mtime;
+ intelligent = 2;
+ }
+ dowork = 1;
+ break;
+
+ case 2:
+ retries = STAT_ATTEMPTS;
+ status = APR_SUCCESS;
+
+ do {
+ if (status != APR_SUCCESS) {
+ apr_sleep(STAT_DELAY);
+ }
+ status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
+ } while (status != APR_SUCCESS && !interrupted && --retries);
+
+ if (status == APR_SUCCESS) {
+ if (previous != info.mtime) {
+ dowork = 1;
+ }
+ previous = info.mtime;
+ break;
+ }
+ intelligent = 1;
+ dowork = 1;
+ break;
+ }
+
+ if (dowork && !interrupted) {
+ apr_off_t nodes = 0;
+ if (!process_dir(path, instance, &nodes) && !interrupted) {
+ purge(path, instance, max, inodes, nodes, round);
+ }
+ else if (!isdaemon && !interrupted) {
+ apr_file_printf(errfile, "An error occurred, cache cleaning "
+ "aborted." APR_EOL_STR);
+ return 1;
+ }
+
+ if (intelligent && !interrupted) {
+ retries = STAT_ATTEMPTS;
+ status = APR_SUCCESS;
+ do {
+ if (status != APR_SUCCESS) {
+ apr_sleep(STAT_DELAY);
+ }
+ status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
+ } while (status != APR_SUCCESS && !interrupted && --retries);
+
+ if (status == APR_SUCCESS) {
+ previous = info.mtime;
+ intelligent = 2;
+ }
+ else {
+ intelligent = 1;
+ }
+ }
+ }
+
+ apr_pool_destroy(instance);
+
+ current = apr_time_now();
+ if (current < now) {
+ delay = repeat;
+ }
+ else if (current - now >= repeat) {
+ delay = repeat;
+ }
+ else {
+ delay = now + repeat - current;
+ }
+
+ /* we can't sleep the whole delay time here apiece as this is racy
+ * with respect to interrupt delivery - think about what happens
+ * if we have tested for an interrupt, then get scheduled
+ * before the apr_sleep() call and while waiting for the cpu
+ * we do get an interrupt
+ */
+ if (isdaemon) {
+ while (delay && !interrupted) {
+ if (delay > APR_USEC_PER_SEC) {
+ apr_sleep(APR_USEC_PER_SEC);
+ delay -= APR_USEC_PER_SEC;
+ }
+ else {
+ apr_sleep(delay);
+ delay = 0;
+ }
+ }
+ }
+ } while (isdaemon && !interrupted);
+
+ if (!isdaemon && interrupted) {
+ apr_file_printf(errfile, "Cache cleaning aborted due to user "
+ "request." APR_EOL_STR);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/support/htcacheclean.dep b/support/htcacheclean.dep
new file mode 100644
index 0000000..0d5d0f8
--- /dev/null
+++ b/support/htcacheclean.dep
@@ -0,0 +1,37 @@
+# Microsoft Developer Studio Generated Dependency File, included by htcacheclean.mak
+
+.\htcacheclean.c : \
+ "..\modules\cache\cache_common.h"\
+ "..\modules\cache\cache_disk_common.h"\
+ "..\srclib\apr-util\include\apr_buckets.h"\
+ "..\srclib\apr-util\include\apr_date.h"\
+ "..\srclib\apr-util\include\apr_md5.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_hash.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_mmap.h"\
+ "..\srclib\apr\include\apr_network_io.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_ring.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_thread_proc.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
diff --git a/support/htcacheclean.dsp b/support/htcacheclean.dsp
new file mode 100644
index 0000000..b1422e0
--- /dev/null
+++ b/support/htcacheclean.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="htcacheclean" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=htcacheclean - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "htcacheclean.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htcacheclean.mak" CFG="htcacheclean - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htcacheclean - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htcacheclean - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htcacheclean - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htcacheclean_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\htcacheclean.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htcacheclean_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\htcacheclean.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "htcacheclean - Win32 Release"
+# Name "htcacheclean - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\htcacheclean.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/htcacheclean.mak b/support/htcacheclean.mak
new file mode 100644
index 0000000..a6fc784
--- /dev/null
+++ b/support/htcacheclean.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on htcacheclean.dsp
+!IF "$(CFG)" == ""
+CFG=htcacheclean - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to htcacheclean - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "htcacheclean - Win32 Release" && "$(CFG)" != "htcacheclean - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htcacheclean.mak" CFG="htcacheclean - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htcacheclean - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htcacheclean - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "htcacheclean - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htcacheclean.obj"
+ -@erase "$(INTDIR)\htcacheclean.res"
+ -@erase "$(INTDIR)\htcacheclean_src.idb"
+ -@erase "$(INTDIR)\htcacheclean_src.pdb"
+ -@erase "$(OUTDIR)\htcacheclean.exe"
+ -@erase "$(OUTDIR)\htcacheclean.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htcacheclean_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htcacheclean.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htcacheclean.pdb" /debug /out:"$(OUTDIR)\htcacheclean.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\htcacheclean.obj" \
+ "$(INTDIR)\htcacheclean.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\htcacheclean.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\htcacheclean.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htcacheclean.exe"
+ if exist .\Release\htcacheclean.exe.manifest mt.exe -manifest .\Release\htcacheclean.exe.manifest -outputresource:.\Release\htcacheclean.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htcacheclean.obj"
+ -@erase "$(INTDIR)\htcacheclean.res"
+ -@erase "$(INTDIR)\htcacheclean_src.idb"
+ -@erase "$(INTDIR)\htcacheclean_src.pdb"
+ -@erase "$(OUTDIR)\htcacheclean.exe"
+ -@erase "$(OUTDIR)\htcacheclean.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htcacheclean_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htcacheclean.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htcacheclean.pdb" /debug /out:"$(OUTDIR)\htcacheclean.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\htcacheclean.obj" \
+ "$(INTDIR)\htcacheclean.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\htcacheclean.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\htcacheclean.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htcacheclean.exe"
+ if exist .\Debug\htcacheclean.exe.manifest mt.exe -manifest .\Debug\htcacheclean.exe.manifest -outputresource:.\Debug\htcacheclean.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("htcacheclean.dep")
+!INCLUDE "htcacheclean.dep"
+!ELSE
+!MESSAGE Warning: cannot find "htcacheclean.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "htcacheclean - Win32 Release" || "$(CFG)" == "htcacheclean - Win32 Debug"
+
+!IF "$(CFG)" == "htcacheclean - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "htcacheclean - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\htcacheclean.c
+
+"$(INTDIR)\htcacheclean.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "htcacheclean - Win32 Release"
+
+
+"$(INTDIR)\htcacheclean.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug"
+
+
+"$(INTDIR)\htcacheclean.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" $(SOURCE)
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/support/htdbm.c b/support/htdbm.c
new file mode 100644
index 0000000..40a3d23
--- /dev/null
+++ b/support/htdbm.c
@@ -0,0 +1,472 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * htdbm.c: simple program for manipulating DBM
+ * password databases for the Apache HTTP server
+ *
+ * Contributed by Mladen Turk <mturk mappingsoft.com>
+ * 12 Oct 2001
+ */
+
+#include "passwd_common.h"
+#include "apr_file_io.h"
+#include "apr_file_info.h"
+#include "apr_pools.h"
+#include "apr_signal.h"
+#include "apr_md5.h"
+#include "apr_sha1.h"
+#include "apr_dbm.h"
+#include "apr_getopt.h"
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if APR_HAVE_STRING_H
+#include <string.h>
+#endif
+#if APR_HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <time.h>
+
+#if APR_CHARSET_EBCDIC
+#include "apr_xlate.h"
+#endif /*APR_CHARSET_EBCDIC*/
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+
+typedef struct htdbm_t htdbm_t;
+
+struct htdbm_t {
+ apr_dbm_t *dbm;
+ struct passwd_ctx ctx;
+#if APR_CHARSET_EBCDIC
+ apr_xlate_t *to_ascii;
+#endif
+ char *filename;
+ char *username;
+ char *comment;
+ char *type;
+ int create;
+ int rdonly;
+};
+
+
+#define HTDBM_MAKE 0
+#define HTDBM_DELETE 1
+#define HTDBM_VERIFY 2
+#define HTDBM_LIST 3
+#define HTDBM_NOFILE 4
+
+static void terminate(void)
+{
+ apr_terminate();
+#ifdef NETWARE
+ pressanykey();
+#endif
+}
+
+static void htdbm_terminate(htdbm_t *htdbm)
+{
+ if (htdbm->dbm)
+ apr_dbm_close(htdbm->dbm);
+ htdbm->dbm = NULL;
+}
+
+static htdbm_t *h;
+
+static void htdbm_interrupted(void)
+{
+ htdbm_terminate(h);
+ fprintf(stderr, "htdbm Interrupted !\n");
+ exit(ERR_INTERRUPTED);
+}
+
+static apr_status_t htdbm_init(apr_pool_t **pool, htdbm_t **hdbm)
+{
+
+#if APR_CHARSET_EBCDIC
+ apr_status_t rv;
+#endif
+
+ apr_pool_create( pool, NULL);
+ apr_pool_abort_set(abort_on_oom, *pool);
+ apr_file_open_stderr(&errfile, *pool);
+ apr_signal(SIGINT, (void (*)(int)) htdbm_interrupted);
+
+ (*hdbm) = (htdbm_t *)apr_pcalloc(*pool, sizeof(htdbm_t));
+ (*hdbm)->ctx.pool = *pool;
+
+#if APR_CHARSET_EBCDIC
+ rv = apr_xlate_open(&((*hdbm)->to_ascii), "ISO-8859-1", APR_DEFAULT_CHARSET, (*hdbm)->ctx.pool);
+ if (rv) {
+ fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", rv);
+ return APR_EGENERAL;
+ }
+ rv = apr_SHA1InitEBCDIC((*hdbm)->to_ascii);
+ if (rv) {
+ fprintf(stderr, "apr_SHA1InitEBCDIC()->%d\n", rv);
+ return APR_EGENERAL;
+ }
+ rv = apr_MD5InitEBCDIC((*hdbm)->to_ascii);
+ if (rv) {
+ fprintf(stderr, "apr_MD5InitEBCDIC()->%d\n", rv);
+ return APR_EGENERAL;
+ }
+#endif /*APR_CHARSET_EBCDIC*/
+
+ /* Set MD5 as default */
+ (*hdbm)->ctx.alg = ALG_APMD5;
+ (*hdbm)->type = "default";
+ return APR_SUCCESS;
+}
+
+static apr_status_t htdbm_open(htdbm_t *htdbm)
+{
+ if (htdbm->create)
+ return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename, APR_DBM_RWCREATE,
+ APR_OS_DEFAULT, htdbm->ctx.pool);
+ else
+ return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename,
+ htdbm->rdonly ? APR_DBM_READONLY : APR_DBM_READWRITE,
+ APR_OS_DEFAULT, htdbm->ctx.pool);
+}
+
+static apr_status_t htdbm_save(htdbm_t *htdbm, int *changed)
+{
+ apr_datum_t key, val;
+
+ if (!htdbm->username)
+ return APR_SUCCESS;
+
+ key.dptr = htdbm->username;
+ key.dsize = strlen(htdbm->username);
+ if (apr_dbm_exists(htdbm->dbm, key))
+ *changed = 1;
+
+ val.dsize = strlen(htdbm->ctx.passwd);
+ if (!htdbm->comment)
+ val.dptr = htdbm->ctx.passwd;
+ else {
+ val.dptr = apr_pstrcat(htdbm->ctx.pool, htdbm->ctx.passwd, ":",
+ htdbm->comment, NULL);
+ val.dsize += (strlen(htdbm->comment) + 1);
+ }
+ return apr_dbm_store(htdbm->dbm, key, val);
+}
+
+static apr_status_t htdbm_del(htdbm_t *htdbm)
+{
+ apr_datum_t key;
+
+ key.dptr = htdbm->username;
+ key.dsize = strlen(htdbm->username);
+ if (!apr_dbm_exists(htdbm->dbm, key))
+ return APR_ENOENT;
+
+ return apr_dbm_delete(htdbm->dbm, key);
+}
+
+static apr_status_t htdbm_verify(htdbm_t *htdbm)
+{
+ apr_datum_t key, val;
+ char *pwd;
+ char *rec, *cmnt;
+
+ key.dptr = htdbm->username;
+ key.dsize = strlen(htdbm->username);
+ if (!apr_dbm_exists(htdbm->dbm, key))
+ return APR_ENOENT;
+ if (apr_dbm_fetch(htdbm->dbm, key, &val) != APR_SUCCESS)
+ return APR_ENOENT;
+ rec = apr_pstrndup(htdbm->ctx.pool, val.dptr, val.dsize);
+ cmnt = strchr(rec, ':');
+ if (cmnt)
+ pwd = apr_pstrndup(htdbm->ctx.pool, rec, cmnt - rec);
+ else
+ pwd = apr_pstrdup(htdbm->ctx.pool, rec);
+ return apr_password_validate(htdbm->ctx.passwd, pwd);
+}
+
+static apr_status_t htdbm_list(htdbm_t *htdbm)
+{
+ apr_status_t rv;
+ apr_datum_t key, val;
+ char *cmnt;
+ int i = 0;
+
+ rv = apr_dbm_firstkey(htdbm->dbm, &key);
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "Empty database -- %s\n", htdbm->filename);
+ return APR_ENOENT;
+ }
+ fprintf(stderr, "Dumping records from database -- %s\n", htdbm->filename);
+ fprintf(stderr, " %-32s Comment\n", "Username");
+ while (key.dptr != NULL) {
+ rv = apr_dbm_fetch(htdbm->dbm, key, &val);
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "Failed getting data from %s\n", htdbm->filename);
+ return APR_EGENERAL;
+ }
+ /* Note: we don't store \0-terminators on our dbm data */
+ fprintf(stderr, " %-32.*s", (int)key.dsize, key.dptr);
+ cmnt = memchr(val.dptr, ':', val.dsize);
+ if (cmnt)
+ fprintf(stderr, " %.*s", (int)(val.dptr+val.dsize - (cmnt+1)), cmnt + 1);
+ fprintf(stderr, "\n");
+ rv = apr_dbm_nextkey(htdbm->dbm, &key);
+ if (rv != APR_SUCCESS)
+ fprintf(stderr, "Failed getting NextKey\n");
+ ++i;
+ }
+
+ fprintf(stderr, "Total #records : %d\n", i);
+ return APR_SUCCESS;
+}
+
+static int htdbm_make(htdbm_t *htdbm)
+{
+ char cpw[MAX_STRING_LEN];
+ int ret;
+
+ htdbm->ctx.out = cpw;
+ htdbm->ctx.out_len = sizeof(cpw);
+ ret = mkhash(&htdbm->ctx);
+ if (ret != 0) {
+ fprintf(stderr, "Error: %s\n", htdbm->ctx.errstr);
+ return ret;
+ }
+ htdbm->ctx.passwd = apr_pstrdup(htdbm->ctx.pool, cpw);
+ return 0;
+}
+
+static apr_status_t htdbm_valid_username(htdbm_t *htdbm)
+{
+ if (!htdbm->username || (strlen(htdbm->username) > 64) || (strlen(htdbm->username) < 1)) {
+ fprintf(stderr, "Invalid username length\n");
+ return APR_EINVAL;
+ }
+ if (strchr(htdbm->username, ':')) {
+ fprintf(stderr, "Username contains invalid characters\n");
+ return APR_EINVAL;
+ }
+ return APR_SUCCESS;
+}
+
+static void htdbm_usage(void)
+{
+ fprintf(stderr,
+ "htdbm -- program for manipulating DBM password databases.\n\n"
+ "Usage: htdbm [-cimBdpstvx] [-C cost] [-TDBTYPE] database username\n"
+ " -b[cmBdptsv] [-C cost] [-TDBTYPE] database username password\n"
+ " -n[imBdpst] [-C cost] username\n"
+ " -nb[mBdpst] [-C cost] username password\n"
+ " -v[imBdps] [-C cost] [-TDBTYPE] database username\n"
+ " -vb[mBdps] [-C cost] [-TDBTYPE] database username password\n"
+ " -x [-TDBTYPE] database username\n"
+ " -l [-TDBTYPE] database\n"
+ "Options:\n"
+ " -c Create a new database.\n"
+ " -n Don't update database; display results on stdout.\n"
+ " -b Use the password from the command line rather than prompting for it.\n"
+ " -i Read password from stdin without verification (for script usage).\n"
+ " -m Force MD5 encryption of the password (default).\n"
+ " -B Force BCRYPT encryption of the password (very secure).\n"
+ " -C Set the computing time used for the bcrypt algorithm\n"
+ " (higher is more secure but slower, default: %d, valid: 4 to 31).\n"
+ " -d Force CRYPT encryption of the password (8 chars max, insecure).\n"
+ " -s Force SHA encryption of the password (insecure).\n"
+ " -p Do not encrypt the password (plaintext, insecure).\n"
+ " -T DBM Type (SDBM|GDBM|DB|default).\n"
+ " -l Display usernames from database on stdout.\n"
+ " -v Verify the username/password.\n"
+ " -x Remove the username record from database.\n"
+ " -t The last param is username comment.\n"
+ "The SHA algorithm does not use a salt and is less secure than the "
+ "MD5 algorithm.\n",
+ BCRYPT_DEFAULT_COST);
+ exit(ERR_SYNTAX);
+}
+
+int main(int argc, const char * const argv[])
+{
+ apr_pool_t *pool;
+ apr_status_t rv;
+ char errbuf[MAX_STRING_LEN];
+ int need_file = 1;
+ int need_user = 1;
+ int need_pwd = 1;
+ int need_cmnt = 0;
+ int changed = 0;
+ int cmd = HTDBM_MAKE;
+ int i, ret, args_left = 2;
+ apr_getopt_t *state;
+ char opt;
+ const char *opt_arg;
+
+ apr_app_initialize(&argc, &argv, NULL);
+ atexit(terminate);
+
+ if ((rv = htdbm_init(&pool, &h)) != APR_SUCCESS) {
+ fprintf(stderr, "Unable to initialize htdbm terminating!\n");
+ apr_strerror(rv, errbuf, sizeof(errbuf));
+ exit(1);
+ }
+
+ rv = apr_getopt_init(&state, pool, argc, argv);
+ if (rv != APR_SUCCESS)
+ exit(ERR_SYNTAX);
+
+ while ((rv = apr_getopt(state, "cnmspdBbtivxlC:T:", &opt, &opt_arg)) == APR_SUCCESS) {
+ switch (opt) {
+ case 'c':
+ h->create = 1;
+ break;
+ case 'n':
+ need_file = 0;
+ cmd = HTDBM_NOFILE;
+ args_left--;
+ break;
+ case 'l':
+ need_pwd = 0;
+ need_user = 0;
+ cmd = HTDBM_LIST;
+ h->rdonly = 1;
+ args_left--;
+ break;
+ case 't':
+ need_cmnt = 1;
+ args_left++;
+ break;
+ case 'T':
+ h->type = apr_pstrdup(h->ctx.pool, opt_arg);
+ break;
+ case 'v':
+ h->rdonly = 1;
+ cmd = HTDBM_VERIFY;
+ break;
+ case 'x':
+ need_pwd = 0;
+ cmd = HTDBM_DELETE;
+ break;
+ default:
+ ret = parse_common_options(&h->ctx, opt, opt_arg);
+ if (ret) {
+ fprintf(stderr, "Error: %s\n", h->ctx.errstr);
+ exit(ret);
+ }
+ }
+ }
+ if (h->ctx.passwd_src == PW_ARG) {
+ need_pwd = 0;
+ args_left++;
+ }
+ /*
+ * Make sure we still have exactly the right number of arguments left
+ * (the filename, the username, and possibly the password if -b was
+ * specified).
+ */
+ i = state->ind;
+ if (rv != APR_EOF || argc - i != args_left)
+ htdbm_usage();
+
+ if (need_file) {
+ h->filename = apr_pstrdup(h->ctx.pool, argv[i++]);
+ if ((rv = htdbm_open(h)) != APR_SUCCESS) {
+ fprintf(stderr, "Error opening database %s\n", h->filename);
+ apr_strerror(rv, errbuf, sizeof(errbuf));
+ fprintf(stderr,"%s\n",errbuf);
+ exit(ERR_FILEPERM);
+ }
+ }
+ if (need_user) {
+ h->username = apr_pstrdup(pool, argv[i++]);
+ if (htdbm_valid_username(h) != APR_SUCCESS)
+ exit(ERR_BADUSER);
+ }
+ if (h->ctx.passwd_src == PW_ARG)
+ h->ctx.passwd = apr_pstrdup(pool, argv[i++]);
+
+ if (need_pwd) {
+ ret = get_password(&h->ctx);
+ if (ret) {
+ fprintf(stderr, "Error: %s\n", h->ctx.errstr);
+ exit(ret);
+ }
+ }
+ if (need_cmnt)
+ h->comment = apr_pstrdup(pool, argv[i++]);
+
+ switch (cmd) {
+ case HTDBM_VERIFY:
+ if ((rv = htdbm_verify(h)) != APR_SUCCESS) {
+ if (APR_STATUS_IS_ENOENT(rv)) {
+ fprintf(stderr, "The user '%s' could not be found in database\n", h->username);
+ exit(ERR_BADUSER);
+ }
+ else {
+ fprintf(stderr, "Password mismatch for user '%s'\n", h->username);
+ exit(ERR_PWMISMATCH);
+ }
+ }
+ else
+ fprintf(stderr, "Password validated for user '%s'\n", h->username);
+ break;
+ case HTDBM_DELETE:
+ if (htdbm_del(h) != APR_SUCCESS) {
+ fprintf(stderr, "Cannot find user '%s' in database\n", h->username);
+ exit(ERR_BADUSER);
+ }
+ h->username = NULL;
+ changed = 1;
+ break;
+ case HTDBM_LIST:
+ htdbm_list(h);
+ break;
+ default:
+ ret = htdbm_make(h);
+ if (ret)
+ exit(ret);
+ break;
+ }
+ if (need_file && !h->rdonly) {
+ if ((rv = htdbm_save(h, &changed)) != APR_SUCCESS) {
+ apr_strerror(rv, errbuf, sizeof(errbuf));
+ exit(ERR_FILEPERM);
+ }
+ fprintf(stdout, "Database %s %s.\n", h->filename,
+ h->create ? "created" : (changed ? "modified" : "updated"));
+ }
+ if (cmd == HTDBM_NOFILE) {
+ if (!need_cmnt) {
+ fprintf(stderr, "%s:%s\n", h->username, h->ctx.passwd);
+ }
+ else {
+ fprintf(stderr, "%s:%s:%s\n", h->username, h->ctx.passwd,
+ h->comment);
+ }
+ }
+ htdbm_terminate(h);
+
+ return 0; /* Suppress compiler warning. */
+}
diff --git a/support/htdbm.dep b/support/htdbm.dep
new file mode 100644
index 0000000..c6b60d8
--- /dev/null
+++ b/support/htdbm.dep
@@ -0,0 +1,58 @@
+# Microsoft Developer Studio Generated Dependency File, included by htdbm.mak
+
+.\htdbm.c : \
+ "..\srclib\apr-util\include\apr_dbm.h"\
+ "..\srclib\apr-util\include\apr_md5.h"\
+ "..\srclib\apr-util\include\apr_sha1.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr-util\include\apu_version.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_version.h"\
+ "..\srclib\apr\include\apr_want.h"\
+ ".\passwd_common.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
+
+.\passwd_common.c : \
+ "..\srclib\apr-util\include\apr_md5.h"\
+ "..\srclib\apr-util\include\apr_sha1.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr-util\include\apu_version.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_version.h"\
+ "..\srclib\apr\include\apr_want.h"\
+ ".\passwd_common.h"\
+
diff --git a/support/htdbm.dsp b/support/htdbm.dsp
new file mode 100644
index 0000000..c1d5494
--- /dev/null
+++ b/support/htdbm.dsp
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="htdbm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=htdbm - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "htdbm.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htdbm.mak" CFG="htdbm - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htdbm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htdbm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htdbm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htdbm_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/htdbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib rpcrt4.lib ws2_32.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\htdbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "htdbm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htdbm_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/htdbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\htdbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "htdbm - Win32 Release"
+# Name "htdbm - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\htdbm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\passwd_common.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/htdbm.mak b/support/htdbm.mak
new file mode 100644
index 0000000..f4379f7
--- /dev/null
+++ b/support/htdbm.mak
@@ -0,0 +1,326 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on htdbm.dsp
+!IF "$(CFG)" == ""
+CFG=htdbm - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to htdbm - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "htdbm - Win32 Release" && "$(CFG)" != "htdbm - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htdbm.mak" CFG="htdbm - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htdbm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htdbm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "htdbm - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htdbm.obj"
+ -@erase "$(INTDIR)\htdbm.res"
+ -@erase "$(INTDIR)\htdbm_src.idb"
+ -@erase "$(INTDIR)\htdbm_src.pdb"
+ -@erase "$(INTDIR)\passwd_common.obj"
+ -@erase "$(OUTDIR)\htdbm.exe"
+ -@erase "$(OUTDIR)\htdbm.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdbm_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdbm.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdbm.pdb" /debug /out:"$(OUTDIR)\htdbm.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\htdbm.obj" \
+ "$(INTDIR)\passwd_common.obj" \
+ "$(INTDIR)\htdbm.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\htdbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\htdbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdbm.exe"
+ if exist .\Release\htdbm.exe.manifest mt.exe -manifest .\Release\htdbm.exe.manifest -outputresource:.\Release\htdbm.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "htdbm - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htdbm.obj"
+ -@erase "$(INTDIR)\htdbm.res"
+ -@erase "$(INTDIR)\htdbm_src.idb"
+ -@erase "$(INTDIR)\htdbm_src.pdb"
+ -@erase "$(INTDIR)\passwd_common.obj"
+ -@erase "$(OUTDIR)\htdbm.exe"
+ -@erase "$(OUTDIR)\htdbm.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdbm_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdbm.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdbm.pdb" /debug /out:"$(OUTDIR)\htdbm.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\htdbm.obj" \
+ "$(INTDIR)\passwd_common.obj" \
+ "$(INTDIR)\htdbm.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\htdbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\htdbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdbm.exe"
+ if exist .\Debug\htdbm.exe.manifest mt.exe -manifest .\Debug\htdbm.exe.manifest -outputresource:.\Debug\htdbm.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("htdbm.dep")
+!INCLUDE "htdbm.dep"
+!ELSE
+!MESSAGE Warning: cannot find "htdbm.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "htdbm - Win32 Release" || "$(CFG)" == "htdbm - Win32 Debug"
+
+!IF "$(CFG)" == "htdbm - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htdbm - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "htdbm - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htdbm - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\htdbm.c
+
+"$(INTDIR)\htdbm.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "htdbm - Win32 Release"
+
+
+"$(INTDIR)\htdbm.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htdbm - Win32 Debug"
+
+
+"$(INTDIR)\htdbm.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\passwd_common.c
+
+"$(INTDIR)\passwd_common.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/support/htdigest.c b/support/htdigest.c
new file mode 100644
index 0000000..43f7054
--- /dev/null
+++ b/support/htdigest.c
@@ -0,0 +1,303 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ ******************************************************************************
+ * NOTE! This program is not safe as a setuid executable! Do not make it
+ * setuid!
+ ******************************************************************************
+ *****************************************************************************/
+/*
+ * htdigest.c: simple program for manipulating digest passwd file for Apache
+ *
+ * by Alexei Kosut, based on htpasswd.c, by Rob McCool
+ */
+
+#include "apr.h"
+#include "apr_file_io.h"
+#include "apr_md5.h"
+#include "apr_lib.h" /* for apr_getpass() */
+#include "apr_general.h"
+#include "apr_signal.h"
+#include "apr_strings.h" /* for apr_pstrdup() */
+
+#define APR_WANT_STDIO
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef WIN32
+#include <conio.h>
+#endif
+
+
+#if APR_CHARSET_EBCDIC
+#define LF '\n'
+#define CR '\r'
+#else
+#define LF 10
+#define CR 13
+#endif /* APR_CHARSET_EBCDIC */
+
+#define MAX_STRING_LEN 256
+#define MAX_LINE_LEN 768
+
+apr_file_t *tfp = NULL;
+apr_file_t *errfile;
+apr_pool_t *cntxt;
+#if APR_CHARSET_EBCDIC
+apr_xlate_t *to_ascii;
+#endif
+
+static void cleanup_tempfile_and_exit(int rc)
+{
+ if (tfp) {
+ apr_file_close(tfp);
+ }
+ exit(rc);
+}
+
+static int getword(char *word, char *line, char stop)
+{
+ int x = 0, y;
+
+ for (x = 0; ((line[x]) && (line[x] != stop)); x++) {
+ if (x == (MAX_STRING_LEN - 1)) {
+ return 1;
+ }
+ word[x] = line[x];
+ }
+
+ word[x] = '\0';
+ if (line[x])
+ ++x;
+ y = 0;
+
+ while ((line[y++] = line[x++]));
+
+ return 0;
+}
+
+static int get_line(char *s, int n, apr_file_t *f)
+{
+ int i = 0;
+ char ch;
+ apr_status_t rv = APR_EINVAL;
+
+ /* we need 2 remaining bytes in buffer */
+ while (i < (n - 2) &&
+ ((rv = apr_file_getc(&ch, f)) == APR_SUCCESS) && (ch != '\n')) {
+ s[i++] = ch;
+ }
+ /* First remaining byte potentially used here */
+ if (ch == '\n')
+ s[i++] = ch;
+ /* Second remaining byte used here */
+ s[i] = '\0';
+
+ if (rv != APR_SUCCESS)
+ return 1;
+
+ return 0;
+}
+
+static void putline(apr_file_t *f, char *l)
+{
+ int x;
+
+ for (x = 0; l[x]; x++)
+ apr_file_putc(l[x], f);
+}
+
+
+static void add_password(const char *user, const char *realm, apr_file_t *f)
+{
+ char *pw;
+ apr_md5_ctx_t context;
+ unsigned char digest[16];
+ char string[MAX_LINE_LEN]; /* this includes room for 2 * ':' + '\0' */
+ char pwin[MAX_STRING_LEN];
+ char pwv[MAX_STRING_LEN];
+ unsigned int i;
+ apr_size_t len = sizeof(pwin);
+
+ if (apr_password_get("New password: ", pwin, &len) != APR_SUCCESS) {
+ apr_file_printf(errfile, "password too long");
+ cleanup_tempfile_and_exit(5);
+ }
+ len = sizeof(pwin);
+ apr_password_get("Re-type new password: ", pwv, &len);
+ if (strcmp(pwin, pwv) != 0) {
+ apr_file_printf(errfile, "They don't match, sorry.\n");
+ cleanup_tempfile_and_exit(1);
+ }
+ pw = pwin;
+ apr_file_printf(f, "%s:%s:", user, realm);
+
+ /* Do MD5 stuff */
+ apr_snprintf(string, sizeof(string), "%s:%s:%s", user, realm, pw);
+
+ apr_md5_init(&context);
+#if APR_CHARSET_EBCDIC
+ apr_md5_set_xlate(&context, to_ascii);
+#endif
+ apr_md5_update(&context, (unsigned char *) string, strlen(string));
+ apr_md5_final(digest, &context);
+
+ for (i = 0; i < 16; i++)
+ apr_file_printf(f, "%02x", digest[i]);
+
+ apr_file_printf(f, "\n");
+}
+
+static void usage(void)
+{
+ apr_file_printf(errfile, "Usage: htdigest [-c] passwordfile realm username\n");
+ apr_file_printf(errfile, "The -c flag creates a new file.\n");
+ exit(1);
+}
+
+static void interrupted(void)
+{
+ apr_file_printf(errfile, "Interrupted.\n");
+ cleanup_tempfile_and_exit(1);
+}
+
+static void terminate(void)
+{
+ apr_terminate();
+#ifdef NETWARE
+ pressanykey();
+#endif
+}
+
+int main(int argc, const char * const argv[])
+{
+ apr_file_t *f;
+ apr_status_t rv;
+ char tn[] = "htdigest.tmp.XXXXXX";
+ char *dirname;
+ char user[MAX_STRING_LEN];
+ char realm[MAX_STRING_LEN];
+ char line[MAX_LINE_LEN];
+ char l[MAX_LINE_LEN];
+ char w[MAX_STRING_LEN];
+ char x[MAX_STRING_LEN];
+ int found;
+
+ apr_app_initialize(&argc, &argv, NULL);
+ atexit(terminate);
+ apr_pool_create(&cntxt, NULL);
+ apr_file_open_stderr(&errfile, cntxt);
+
+#if APR_CHARSET_EBCDIC
+ rv = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, cntxt);
+ if (rv) {
+ apr_file_printf(errfile, "apr_xlate_open(): %pm (%d)\n",
+ &rv, rv);
+ exit(1);
+ }
+#endif
+
+ apr_signal(SIGINT, (void (*)(int)) interrupted);
+ if (argc == 5) {
+ if (strcmp(argv[1], "-c"))
+ usage();
+ rv = apr_file_open(&f, argv[2], APR_WRITE | APR_CREATE,
+ APR_OS_DEFAULT, cntxt);
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile, "Could not open passwd file %s for writing: %pm\n",
+ argv[2], &rv);
+ exit(1);
+ }
+ apr_cpystrn(user, argv[4], sizeof(user));
+ apr_cpystrn(realm, argv[3], sizeof(realm));
+ apr_file_printf(errfile, "Adding password for %s in realm %s.\n",
+ user, realm);
+ add_password(user, realm, f);
+ apr_file_close(f);
+ exit(0);
+ }
+ else if (argc != 4)
+ usage();
+
+ if (apr_temp_dir_get((const char**)&dirname, cntxt) != APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: could not determine temp dir\n",
+ argv[0]);
+ exit(1);
+ }
+ dirname = apr_psprintf(cntxt, "%s/%s", dirname, tn);
+
+ if (apr_file_mktemp(&tfp, dirname, 0, cntxt) != APR_SUCCESS) {
+ apr_file_printf(errfile, "Could not open temp file %s.\n", dirname);
+ exit(1);
+ }
+
+ if (apr_file_open(&f, argv[1], APR_READ, APR_OS_DEFAULT, cntxt) != APR_SUCCESS) {
+ apr_file_printf(errfile,
+ "Could not open passwd file %s for reading.\n", argv[1]);
+ apr_file_printf(errfile, "Use -c option to create new one.\n");
+ cleanup_tempfile_and_exit(1);
+ }
+ apr_cpystrn(user, argv[3], sizeof(user));
+ apr_cpystrn(realm, argv[2], sizeof(realm));
+
+ found = 0;
+ while (!(get_line(line, sizeof(line), f))) {
+ if (found || (line[0] == '#') || (!line[0])) {
+ putline(tfp, line);
+ continue;
+ }
+ strcpy(l, line);
+ if (getword(w, l, ':') || getword(x, l, ':')) {
+ apr_file_printf(errfile, "The following line contains a string longer than the "
+ "allowed maximum size (%i): %s\n", MAX_STRING_LEN - 1, line);
+ cleanup_tempfile_and_exit(1);
+ }
+ if (strcmp(user, w) || strcmp(realm, x)) {
+ putline(tfp, line);
+ continue;
+ }
+ else {
+ apr_file_printf(errfile, "Changing password for user %s in realm %s\n",
+ user, realm);
+ add_password(user, realm, tfp);
+ found = 1;
+ }
+ }
+ if (!found) {
+ apr_file_printf(errfile, "Adding user %s in realm %s\n", user, realm);
+ add_password(user, realm, tfp);
+ }
+ apr_file_close(f);
+
+ /* The temporary file has all the data, just copy it to the new location.
+ */
+ if (apr_file_copy(dirname, argv[1], APR_OS_DEFAULT, cntxt) !=
+ APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: unable to update file %s\n",
+ argv[0], argv[1]);
+ }
+ apr_file_close(tfp);
+
+ return 0;
+}
diff --git a/support/htdigest.dep b/support/htdigest.dep
new file mode 100644
index 0000000..2bde4ac
--- /dev/null
+++ b/support/htdigest.dep
@@ -0,0 +1,27 @@
+# Microsoft Developer Studio Generated Dependency File, included by htdigest.mak
+
+.\htdigest.c : \
+ "..\srclib\apr-util\include\apr_md5.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
diff --git a/support/htdigest.dsp b/support/htdigest.dsp
new file mode 100644
index 0000000..bc3cffe
--- /dev/null
+++ b/support/htdigest.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="htdigest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=htdigest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "htdigest.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htdigest - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htdigest_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/htdigest.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\htdigest.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htdigest_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/htdigest.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\htdigest.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "htdigest - Win32 Release"
+# Name "htdigest - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\htdigest.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/htdigest.mak b/support/htdigest.mak
new file mode 100644
index 0000000..acccd23
--- /dev/null
+++ b/support/htdigest.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on htdigest.dsp
+!IF "$(CFG)" == ""
+CFG=htdigest - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to htdigest - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "htdigest - Win32 Release" && "$(CFG)" != "htdigest - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htdigest - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htdigest.obj"
+ -@erase "$(INTDIR)\htdigest.res"
+ -@erase "$(INTDIR)\htdigest_src.idb"
+ -@erase "$(INTDIR)\htdigest_src.pdb"
+ -@erase "$(OUTDIR)\htdigest.exe"
+ -@erase "$(OUTDIR)\htdigest.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdigest_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdigest.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdigest.pdb" /debug /out:"$(OUTDIR)\htdigest.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\htdigest.obj" \
+ "$(INTDIR)\htdigest.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\htdigest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\htdigest.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdigest.exe"
+ if exist .\Release\htdigest.exe.manifest mt.exe -manifest .\Release\htdigest.exe.manifest -outputresource:.\Release\htdigest.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htdigest.obj"
+ -@erase "$(INTDIR)\htdigest.res"
+ -@erase "$(INTDIR)\htdigest_src.idb"
+ -@erase "$(INTDIR)\htdigest_src.pdb"
+ -@erase "$(OUTDIR)\htdigest.exe"
+ -@erase "$(OUTDIR)\htdigest.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdigest_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdigest.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdigest.pdb" /debug /out:"$(OUTDIR)\htdigest.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\htdigest.obj" \
+ "$(INTDIR)\htdigest.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\htdigest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\htdigest.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdigest.exe"
+ if exist .\Debug\htdigest.exe.manifest mt.exe -manifest .\Debug\htdigest.exe.manifest -outputresource:.\Debug\htdigest.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("htdigest.dep")
+!INCLUDE "htdigest.dep"
+!ELSE
+!MESSAGE Warning: cannot find "htdigest.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "htdigest - Win32 Release" || "$(CFG)" == "htdigest - Win32 Debug"
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\htdigest.c
+
+"$(INTDIR)\htdigest.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+
+"$(INTDIR)\htdigest.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+
+"$(INTDIR)\htdigest.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" $(SOURCE)
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/support/htpasswd.c b/support/htpasswd.c
new file mode 100644
index 0000000..7dd5af9
--- /dev/null
+++ b/support/htpasswd.c
@@ -0,0 +1,524 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ ******************************************************************************
+ * NOTE! This program is not safe as a setuid executable! Do not make it
+ * setuid!
+ ******************************************************************************
+ *****************************************************************************/
+/*
+ * htpasswd.c: simple program for manipulating password file for
+ * the Apache HTTP server
+ *
+ * Originally by Rob McCool
+ *
+ * Exit values:
+ * 0: Success
+ * 1: Failure; file access/permission problem
+ * 2: Failure; command line syntax problem (usage message issued)
+ * 3: Failure; password verification failure
+ * 4: Failure; operation interrupted (such as with CTRL/C)
+ * 5: Failure; buffer would overflow (username, filename, or computed
+ * record too long)
+ * 6: Failure; username contains illegal or reserved characters
+ * 7: Failure; file is not a valid htpasswd file
+ */
+
+#include "passwd_common.h"
+#include "apr_signal.h"
+#include "apr_getopt.h"
+
+#if APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#include "apr_md5.h"
+#include "apr_sha1.h"
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if APR_HAVE_STRING_H
+#include <string.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WIN32
+#include <conio.h>
+#define unlink _unlink
+#endif
+
+#define APHTP_NEWFILE 1
+#define APHTP_NOFILE 2
+#define APHTP_DELUSER 4
+#define APHTP_VERIFY 8
+
+apr_file_t *ftemp = NULL;
+
+static int mkrecord(struct passwd_ctx *ctx, char *user)
+{
+ char hash_str[MAX_STRING_LEN];
+ int ret;
+
+ ctx->out = hash_str;
+ ctx->out_len = sizeof(hash_str);
+
+ ret = mkhash(ctx);
+ if (ret) {
+ ctx->out = NULL;
+ ctx->out_len = 0;
+ return ret;
+ }
+
+ ctx->out = apr_pstrcat(ctx->pool, user, ":", hash_str, NL, NULL);
+ ctx->out_len = strlen(ctx->out);
+ if (ctx->out_len >= MAX_STRING_LEN) {
+ ctx->errstr = "resultant record too long";
+ return ERR_OVERFLOW;
+ }
+ return 0;
+}
+
+static void usage(void)
+{
+ apr_file_printf(errfile, "Usage:" NL
+ "\thtpasswd [-cimBdpsDv] [-C cost] passwordfile username" NL
+ "\thtpasswd -b[cmBdpsDv] [-C cost] passwordfile username password" NL
+ NL
+ "\thtpasswd -n[imBdps] [-C cost] username" NL
+ "\thtpasswd -nb[mBdps] [-C cost] username password" NL
+ " -c Create a new file." NL
+ " -n Don't update file; display results on stdout." NL
+ " -b Use the password from the command line rather than prompting "
+ "for it." NL
+ " -i Read password from stdin without verification (for script usage)." NL
+ " -m Force MD5 encryption of the password (default)." NL
+ " -B Force bcrypt encryption of the password (very secure)." NL
+ " -C Set the computing time used for the bcrypt algorithm" NL
+ " (higher is more secure but slower, default: %d, valid: 4 to 17)." NL
+ " -d Force CRYPT encryption of the password (8 chars max, insecure)." NL
+ " -s Force SHA encryption of the password (insecure)." NL
+ " -p Do not encrypt the password (plaintext, insecure)." NL
+ " -D Delete the specified user." NL
+ " -v Verify password for the specified user." NL
+ "On other systems than Windows and NetWare the '-p' flag will "
+ "probably not work." NL
+ "The SHA algorithm does not use a salt and is less secure than the "
+ "MD5 algorithm." NL,
+ BCRYPT_DEFAULT_COST
+ );
+ exit(ERR_SYNTAX);
+}
+
+/*
+ * Check to see if the specified file can be opened for the given
+ * access.
+ */
+static int accessible(apr_pool_t *pool, char *fname, int mode)
+{
+ apr_file_t *f = NULL;
+
+ if (apr_file_open(&f, fname, mode, APR_OS_DEFAULT, pool) != APR_SUCCESS) {
+ return 0;
+ }
+ apr_file_close(f);
+ return 1;
+}
+
+/*
+ * Return true if the named file exists, regardless of permissions.
+ */
+static int exists(char *fname, apr_pool_t *pool)
+{
+ apr_finfo_t sbuf;
+ apr_status_t check;
+
+ check = apr_stat(&sbuf, fname, APR_FINFO_TYPE, pool);
+ return ((check || sbuf.filetype != APR_REG) ? 0 : 1);
+}
+
+static void terminate(void)
+{
+ apr_terminate();
+#ifdef NETWARE
+ pressanykey();
+#endif
+}
+
+static void check_args(int argc, const char *const argv[],
+ struct passwd_ctx *ctx, unsigned *mask, char **user,
+ char **pwfilename)
+{
+ const char *arg;
+ int args_left = 2;
+ int i, ret;
+ apr_getopt_t *state;
+ apr_status_t rv;
+ char opt;
+ const char *opt_arg;
+ apr_pool_t *pool = ctx->pool;
+
+ rv = apr_getopt_init(&state, pool, argc, argv);
+ if (rv != APR_SUCCESS)
+ exit(ERR_SYNTAX);
+
+ while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) {
+ switch (opt) {
+ case 'c':
+ *mask |= APHTP_NEWFILE;
+ break;
+ case 'n':
+ args_left--;
+ *mask |= APHTP_NOFILE;
+ break;
+ case 'D':
+ *mask |= APHTP_DELUSER;
+ break;
+ case 'v':
+ *mask |= APHTP_VERIFY;
+ break;
+ default:
+ ret = parse_common_options(ctx, opt, opt_arg);
+ if (ret) {
+ apr_file_printf(errfile, "%s: %s" NL, argv[0], ctx->errstr);
+ exit(ret);
+ }
+ }
+ }
+ if (ctx->passwd_src == PW_ARG)
+ args_left++;
+ if (rv != APR_EOF)
+ usage();
+
+ if ((*mask) & (*mask - 1)) {
+ /* not a power of two, i.e. more than one flag specified */
+ apr_file_printf(errfile, "%s: only one of -c -n -v -D may be specified" NL,
+ argv[0]);
+ exit(ERR_SYNTAX);
+ }
+ if ((*mask & APHTP_VERIFY) && ctx->passwd_src == PW_PROMPT)
+ ctx->passwd_src = PW_PROMPT_VERIFY;
+
+ /*
+ * Make sure we still have exactly the right number of arguments left
+ * (the filename, the username, and possibly the password if -b was
+ * specified).
+ */
+ i = state->ind;
+ if ((argc - i) != args_left) {
+ usage();
+ }
+
+ if (!(*mask & APHTP_NOFILE)) {
+ if (strlen(argv[i]) > (APR_PATH_MAX - 1)) {
+ apr_file_printf(errfile, "%s: filename too long" NL, argv[0]);
+ exit(ERR_OVERFLOW);
+ }
+ *pwfilename = apr_pstrdup(pool, argv[i++]);
+ }
+ if (strlen(argv[i]) > (MAX_STRING_LEN - 1)) {
+ apr_file_printf(errfile, "%s: username too long (> %d)" NL,
+ argv[0], MAX_STRING_LEN - 1);
+ exit(ERR_OVERFLOW);
+ }
+ *user = apr_pstrdup(pool, argv[i++]);
+ if ((arg = strchr(*user, ':')) != NULL) {
+ apr_file_printf(errfile, "%s: username contains illegal "
+ "character '%c'" NL, argv[0], *arg);
+ exit(ERR_BADUSER);
+ }
+ if (ctx->passwd_src == PW_ARG) {
+ if (strlen(argv[i]) > (MAX_STRING_LEN - 1)) {
+ apr_file_printf(errfile, "%s: password too long (> %d)" NL,
+ argv[0], MAX_STRING_LEN);
+ exit(ERR_OVERFLOW);
+ }
+ ctx->passwd = apr_pstrdup(pool, argv[i]);
+ }
+}
+
+static int verify(struct passwd_ctx *ctx, const char *hash)
+{
+ apr_status_t rv;
+ int ret;
+
+ if (ctx->passwd == NULL && (ret = get_password(ctx)) != 0)
+ return ret;
+ rv = apr_password_validate(ctx->passwd, hash);
+ if (rv == APR_SUCCESS)
+ return 0;
+ if (APR_STATUS_IS_EMISMATCH(rv)) {
+ ctx->errstr = "password verification failed";
+ return ERR_PWMISMATCH;
+ }
+ ctx->errstr = apr_psprintf(ctx->pool, "Could not verify password: %pm",
+ &rv);
+ return ERR_GENERAL;
+}
+
+/*
+ * Let's do it. We end up doing a lot of file opening and closing,
+ * but what do we care? This application isn't run constantly.
+ */
+int main(int argc, const char * const argv[])
+{
+ apr_file_t *fpw = NULL;
+ char line[MAX_STRING_LEN];
+ char *pwfilename = NULL;
+ char *user = NULL;
+ char tn[] = "htpasswd.tmp.XXXXXX";
+ char *dirname;
+ char *scratch, cp[MAX_STRING_LEN];
+ int found = 0;
+ int i;
+ unsigned mask = 0;
+ apr_pool_t *pool;
+ int existing_file = 0;
+ struct passwd_ctx ctx = { 0 };
+#if APR_CHARSET_EBCDIC
+ apr_status_t rv;
+ apr_xlate_t *to_ascii;
+#endif
+
+ apr_app_initialize(&argc, &argv, NULL);
+ atexit(terminate);
+ apr_pool_create(&pool, NULL);
+ apr_pool_abort_set(abort_on_oom, pool);
+ apr_file_open_stderr(&errfile, pool);
+ ctx.pool = pool;
+ ctx.alg = ALG_APMD5;
+
+#if APR_CHARSET_EBCDIC
+ rv = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, pool);
+ if (rv) {
+ apr_file_printf(errfile, "apr_xlate_open(to ASCII)->%d" NL, rv);
+ exit(1);
+ }
+ rv = apr_SHA1InitEBCDIC(to_ascii);
+ if (rv) {
+ apr_file_printf(errfile, "apr_SHA1InitEBCDIC()->%d" NL, rv);
+ exit(1);
+ }
+ rv = apr_MD5InitEBCDIC(to_ascii);
+ if (rv) {
+ apr_file_printf(errfile, "apr_MD5InitEBCDIC()->%d" NL, rv);
+ exit(1);
+ }
+#endif /*APR_CHARSET_EBCDIC*/
+
+ check_args(argc, argv, &ctx, &mask, &user, &pwfilename);
+
+ /*
+ * Only do the file checks if we're supposed to frob it.
+ */
+ if (!(mask & APHTP_NOFILE)) {
+ existing_file = exists(pwfilename, pool);
+ if (existing_file && (mask & APHTP_VERIFY) == 0) {
+ /*
+ * Check that this existing file is readable and writable.
+ */
+ if (!accessible(pool, pwfilename, APR_FOPEN_READ|APR_FOPEN_WRITE)) {
+ apr_file_printf(errfile, "%s: cannot open file %s for "
+ "read/write access" NL, argv[0], pwfilename);
+ exit(ERR_FILEPERM);
+ }
+ }
+ else if (existing_file && (mask & APHTP_VERIFY) != 0) {
+ /*
+ * Check that this existing file is readable.
+ */
+ if (!accessible(pool, pwfilename, APR_FOPEN_READ)) {
+ apr_file_printf(errfile, "%s: cannot open file %s for "
+ "read access" NL, argv[0], pwfilename);
+ exit(ERR_FILEPERM);
+ }
+ }
+ else {
+ /*
+ * Error out if -c was omitted for this non-existent file.
+ */
+ if (!(mask & APHTP_NEWFILE)) {
+ apr_file_printf(errfile,
+ "%s: cannot modify file %s; use '-c' to create it" NL,
+ argv[0], pwfilename);
+ exit(ERR_FILEPERM);
+ }
+ /*
+ * As it doesn't exist yet, verify that we can create it.
+ */
+ if (!accessible(pool, pwfilename, APR_FOPEN_WRITE|APR_FOPEN_CREATE)) {
+ apr_file_printf(errfile, "%s: cannot create file %s" NL,
+ argv[0], pwfilename);
+ exit(ERR_FILEPERM);
+ }
+ }
+ }
+
+ /*
+ * All the file access checks (if any) have been made. Time to go to work;
+ * try to create the record for the username in question. If that
+ * fails, there's no need to waste any time on file manipulations.
+ * Any error message text is returned in the record buffer, since
+ * the mkrecord() routine doesn't have access to argv[].
+ */
+ if ((mask & (APHTP_DELUSER|APHTP_VERIFY)) == 0) {
+ i = mkrecord(&ctx, user);
+ if (i != 0) {
+ apr_file_printf(errfile, "%s: %s" NL, argv[0], ctx.errstr);
+ exit(i);
+ }
+ if (mask & APHTP_NOFILE) {
+ printf("%s" NL, ctx.out);
+ exit(0);
+ }
+ }
+
+ if ((mask & APHTP_VERIFY) == 0) {
+ /*
+ * We can access the files the right way, and we have a record
+ * to add or update. Let's do it..
+ */
+ if (apr_temp_dir_get((const char**)&dirname, pool) != APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: could not determine temp dir" NL,
+ argv[0]);
+ exit(ERR_FILEPERM);
+ }
+ dirname = apr_psprintf(pool, "%s/%s", dirname, tn);
+
+ if (apr_file_mktemp(&ftemp, dirname, 0, pool) != APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: unable to create temporary file %s" NL,
+ argv[0], dirname);
+ exit(ERR_FILEPERM);
+ }
+ }
+
+ /*
+ * If we're not creating a new file, copy records from the existing
+ * one to the temporary file until we find the specified user.
+ */
+ if (existing_file && !(mask & APHTP_NEWFILE)) {
+ if (apr_file_open(&fpw, pwfilename, APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, pool) != APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: unable to read file %s" NL,
+ argv[0], pwfilename);
+ exit(ERR_FILEPERM);
+ }
+ while (apr_file_gets(line, sizeof(line), fpw) == APR_SUCCESS) {
+ char *colon;
+
+ strcpy(cp, line);
+ scratch = cp;
+ while (apr_isspace(*scratch)) {
+ ++scratch;
+ }
+
+ if (!*scratch || (*scratch == '#')) {
+ putline(ftemp, line);
+ continue;
+ }
+ /*
+ * See if this is our user.
+ */
+ colon = strchr(scratch, ':');
+ if (colon != NULL) {
+ *colon = '\0';
+ }
+ else {
+ /*
+ * If we've not got a colon on the line, this could well
+ * not be a valid htpasswd file.
+ * We should bail at this point.
+ */
+ apr_file_printf(errfile, "%s: The file %s does not appear "
+ "to be a valid htpasswd file." NL,
+ argv[0], pwfilename);
+ apr_file_close(fpw);
+ exit(ERR_INVALID);
+ }
+ if (strcmp(user, scratch) != 0) {
+ putline(ftemp, line);
+ continue;
+ }
+ else {
+ /* We found the user we were looking for */
+ found++;
+ if ((mask & APHTP_DELUSER)) {
+ /* Delete entry from the file */
+ apr_file_printf(errfile, "Deleting ");
+ }
+ else if ((mask & APHTP_VERIFY)) {
+ /* Verify */
+ char *hash = colon + 1;
+ size_t len;
+
+ len = strcspn(hash, "\r\n");
+ if (len == 0) {
+ apr_file_printf(errfile, "Empty hash for user %s" NL,
+ user);
+ exit(ERR_INVALID);
+ }
+ hash[len] = '\0';
+
+ i = verify(&ctx, hash);
+ if (i != 0) {
+ apr_file_printf(errfile, "%s" NL, ctx.errstr);
+ exit(i);
+ }
+ }
+ else {
+ /* Update entry */
+ apr_file_printf(errfile, "Updating ");
+ putline(ftemp, ctx.out);
+ }
+ }
+ }
+ apr_file_close(fpw);
+ }
+ if (!found) {
+ if (mask & APHTP_DELUSER) {
+ apr_file_printf(errfile, "User %s not found" NL, user);
+ exit(0);
+ }
+ else if (mask & APHTP_VERIFY) {
+ apr_file_printf(errfile, "User %s not found" NL, user);
+ exit(ERR_BADUSER);
+ }
+ else {
+ apr_file_printf(errfile, "Adding ");
+ putline(ftemp, ctx.out);
+ }
+ }
+ if (mask & APHTP_VERIFY) {
+ apr_file_printf(errfile, "Password for user %s correct." NL, user);
+ exit(0);
+ }
+
+ apr_file_printf(errfile, "password for user %s" NL, user);
+
+ /* The temporary file has all the data, just copy it to the new location.
+ */
+ if (apr_file_copy(dirname, pwfilename, APR_OS_DEFAULT, pool) !=
+ APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: unable to update file %s" NL,
+ argv[0], pwfilename);
+ exit(ERR_FILEPERM);
+ }
+ apr_file_close(ftemp);
+ return 0;
+}
diff --git a/support/htpasswd.dep b/support/htpasswd.dep
new file mode 100644
index 0000000..6e3e4fa
--- /dev/null
+++ b/support/htpasswd.dep
@@ -0,0 +1,57 @@
+# Microsoft Developer Studio Generated Dependency File, included by htpasswd.mak
+
+.\htpasswd.c : \
+ "..\srclib\apr-util\include\apr_md5.h"\
+ "..\srclib\apr-util\include\apr_sha1.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr-util\include\apu_version.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_version.h"\
+ "..\srclib\apr\include\apr_want.h"\
+ ".\passwd_common.h"\
+
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
+
+.\passwd_common.c : \
+ "..\srclib\apr-util\include\apr_md5.h"\
+ "..\srclib\apr-util\include\apr_sha1.h"\
+ "..\srclib\apr-util\include\apr_xlate.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr-util\include\apu_version.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_version.h"\
+ "..\srclib\apr\include\apr_want.h"\
+ ".\passwd_common.h"\
+
diff --git a/support/htpasswd.dsp b/support/htpasswd.dsp
new file mode 100644
index 0000000..b605669
--- /dev/null
+++ b/support/htpasswd.dsp
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="htpasswd" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=htpasswd - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "htpasswd.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htpasswd.mak" CFG="htpasswd - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htpasswd - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htpasswd - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htpasswd_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\htpasswd.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htpasswd_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\htpasswd.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "htpasswd - Win32 Release"
+# Name "htpasswd - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\htpasswd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\passwd_common.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/htpasswd.mak b/support/htpasswd.mak
new file mode 100644
index 0000000..a492324
--- /dev/null
+++ b/support/htpasswd.mak
@@ -0,0 +1,326 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on htpasswd.dsp
+!IF "$(CFG)" == ""
+CFG=htpasswd - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to htpasswd - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "htpasswd - Win32 Release" && "$(CFG)" != "htpasswd - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htpasswd.mak" CFG="htpasswd - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htpasswd - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "htpasswd - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htpasswd.obj"
+ -@erase "$(INTDIR)\htpasswd.res"
+ -@erase "$(INTDIR)\htpasswd_src.idb"
+ -@erase "$(INTDIR)\htpasswd_src.pdb"
+ -@erase "$(INTDIR)\passwd_common.obj"
+ -@erase "$(OUTDIR)\htpasswd.exe"
+ -@erase "$(OUTDIR)\htpasswd.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htpasswd_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htpasswd.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htpasswd.pdb" /debug /out:"$(OUTDIR)\htpasswd.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\htpasswd.obj" \
+ "$(INTDIR)\passwd_common.obj" \
+ "$(INTDIR)\htpasswd.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\htpasswd.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\htpasswd.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htpasswd.exe"
+ if exist .\Release\htpasswd.exe.manifest mt.exe -manifest .\Release\htpasswd.exe.manifest -outputresource:.\Release\htpasswd.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\htpasswd.obj"
+ -@erase "$(INTDIR)\htpasswd.res"
+ -@erase "$(INTDIR)\htpasswd_src.idb"
+ -@erase "$(INTDIR)\htpasswd_src.pdb"
+ -@erase "$(INTDIR)\passwd_common.obj"
+ -@erase "$(OUTDIR)\htpasswd.exe"
+ -@erase "$(OUTDIR)\htpasswd.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htpasswd_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htpasswd.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htpasswd.pdb" /debug /out:"$(OUTDIR)\htpasswd.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\htpasswd.obj" \
+ "$(INTDIR)\passwd_common.obj" \
+ "$(INTDIR)\htpasswd.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\htpasswd.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\htpasswd.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htpasswd.exe"
+ if exist .\Debug\htpasswd.exe.manifest mt.exe -manifest .\Debug\htpasswd.exe.manifest -outputresource:.\Debug\htpasswd.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("htpasswd.dep")
+!INCLUDE "htpasswd.dep"
+!ELSE
+!MESSAGE Warning: cannot find "htpasswd.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "htpasswd - Win32 Release" || "$(CFG)" == "htpasswd - Win32 Debug"
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=.\htpasswd.c
+
+"$(INTDIR)\htpasswd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+
+"$(INTDIR)\htpasswd.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+
+"$(INTDIR)\htpasswd.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\passwd_common.c
+
+"$(INTDIR)\passwd_common.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/support/httxt2dbm.c b/support/httxt2dbm.c
new file mode 100644
index 0000000..387418b
--- /dev/null
+++ b/support/httxt2dbm.c
@@ -0,0 +1,335 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * httxt2dbm.c: simple program for converting RewriteMap text files to DBM
+ * Rewrite databases for the Apache HTTP server
+ *
+ */
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_file_io.h"
+#include "apr_file_info.h"
+#include "apr_pools.h"
+#include "apr_getopt.h"
+#include "apu.h"
+#include "apr_dbm.h"
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h> /* for atexit() */
+#endif
+
+static const char *input;
+static const char *output;
+static const char *format;
+static const char *shortname;
+static apr_file_t *errfile;
+static int verbose;
+
+/* From mod_rewrite.c */
+#ifndef REWRITE_MAX_TXT_MAP_LINE
+#define REWRITE_MAX_TXT_MAP_LINE 1024
+#endif
+
+#define NL APR_EOL_STR
+
+#define AVAIL "available"
+#define UNAVAIL "unavailable"
+
+static void usage(void)
+{
+ const char *have_sdbm;
+ const char *have_gdbm;
+ const char *have_ndbm;
+ const char *have_db;
+
+#if APU_HAVE_SDBM
+ have_sdbm = AVAIL;
+#else
+ have_sdbm = UNAVAIL;
+#endif
+#if APU_HAVE_GDBM
+ have_gdbm = AVAIL;
+#else
+ have_gdbm = UNAVAIL;
+#endif
+#if APU_HAVE_NDBM
+ have_ndbm = AVAIL;
+#else
+ have_ndbm = UNAVAIL;
+#endif
+#if APU_HAVE_DB
+ have_db = AVAIL;
+#else
+ have_db = UNAVAIL;
+#endif
+
+ apr_file_printf(errfile,
+ "%s -- Program to Create DBM Files for use by RewriteMap" NL
+ "Usage: %s [-v] [-f format] -i SOURCE_TXT -o OUTPUT_DBM" NL
+ NL
+ "Options: " NL
+ " -v More verbose output" NL
+ NL
+ " -i Source Text File. If '-', use stdin." NL
+ NL
+ " -o Output DBM." NL
+ NL
+ " -f DBM Format. If not specified, will use the APR Default." NL
+ " GDBM for GDBM files (%s)" NL
+ " SDBM for SDBM files (%s)" NL
+ " DB for berkeley DB files (%s)" NL
+ " NDBM for NDBM files (%s)" NL
+ " default for the default DBM type" NL
+ NL,
+ shortname,
+ shortname,
+ have_gdbm,
+ have_sdbm,
+ have_db,
+ have_ndbm);
+}
+
+
+static apr_status_t to_dbm(apr_dbm_t *dbm, apr_file_t *fp, apr_pool_t *pool)
+{
+ apr_status_t rv = APR_SUCCESS;
+ char line[REWRITE_MAX_TXT_MAP_LINE + 1]; /* +1 for \0 */
+ apr_datum_t dbmkey;
+ apr_datum_t dbmval;
+ apr_pool_t* p;
+
+ apr_pool_create(&p, pool);
+
+ while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) {
+ char *c, *value;
+
+ if (*line == '#' || apr_isspace(*line)) {
+ continue;
+ }
+
+ c = line;
+
+ while (*c && !apr_isspace(*c)) {
+ ++c;
+ }
+
+ if (!*c) {
+ /* no value. solid line of data. */
+ continue;
+ }
+
+ dbmkey.dptr = apr_pstrmemdup(p, line, c - line);
+ dbmkey.dsize = (c - line);
+
+ while (apr_isspace(*c)) {
+ ++c;
+ }
+
+ if (!*c) {
+ apr_pool_clear(p);
+ continue;
+ }
+
+ value = c;
+
+ while (*c && !apr_isspace(*c)) {
+ ++c;
+ }
+
+ dbmval.dptr = apr_pstrmemdup(p, value, c - value);
+ dbmval.dsize = (c - value);
+
+ if (verbose) {
+ apr_file_printf(errfile, " '%s' -> '%s'" NL,
+ dbmkey.dptr, dbmval.dptr);
+ }
+
+ rv = apr_dbm_store(dbm, dbmkey, dbmval);
+
+ apr_pool_clear(p);
+
+ if (rv != APR_SUCCESS) {
+ break;
+ }
+ }
+
+ return rv;
+}
+
+int main(int argc, const char *const argv[])
+{
+ apr_pool_t *pool;
+ apr_status_t rv = APR_SUCCESS;
+ apr_getopt_t *opt;
+ const char *opt_arg;
+ char ch;
+ apr_file_t *infile;
+ apr_dbm_t *outdbm;
+
+ apr_app_initialize(&argc, &argv, NULL);
+ atexit(apr_terminate);
+
+ verbose = 0;
+ format = NULL;
+ input = NULL;
+ output = NULL;
+
+ apr_pool_create(&pool, NULL);
+
+ if (argc) {
+ shortname = apr_filepath_name_get(argv[0]);
+ }
+ else {
+ shortname = "httxt2dbm";
+ }
+
+ apr_file_open_stderr(&errfile, pool);
+ rv = apr_getopt_init(&opt, pool, argc, argv);
+
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile, "Error: apr_getopt_init failed." NL NL);
+ return 1;
+ }
+
+ if (argc <= 1) {
+ usage();
+ return 1;
+ }
+
+ while ((rv = apr_getopt(opt, "vf::i::o::", &ch, &opt_arg)) == APR_SUCCESS) {
+ switch (ch) {
+ case 'v':
+ if (verbose) {
+ apr_file_printf(errfile, "Error: -v can only be passed once" NL NL);
+ usage();
+ return 1;
+ }
+ verbose = 1;
+ break;
+ case 'f':
+ if (format) {
+ apr_file_printf(errfile, "Error: -f can only be passed once" NL NL);
+ usage();
+ return 1;
+ }
+ format = apr_pstrdup(pool, opt_arg);
+ break;
+ case 'i':
+ if (input) {
+ apr_file_printf(errfile, "Error: -i can only be passed once" NL NL);
+ usage();
+ return 1;
+ }
+ input = apr_pstrdup(pool, opt_arg);
+ break;
+ case 'o':
+ if (output) {
+ apr_file_printf(errfile, "Error: -o can only be passed once" NL NL);
+ usage();
+ return 1;
+ }
+ output = apr_pstrdup(pool, opt_arg);
+ break;
+ }
+ }
+
+ if (rv != APR_EOF) {
+ apr_file_printf(errfile, "Error: Parsing Arguments Failed" NL NL);
+ usage();
+ return 1;
+ }
+
+ if (!input) {
+ apr_file_printf(errfile, "Error: No input file specified." NL NL);
+ usage();
+ return 1;
+ }
+
+ if (!output) {
+ apr_file_printf(errfile, "Error: No output DBM specified." NL NL);
+ usage();
+ return 1;
+ }
+
+ if (!format) {
+ format = "default";
+ }
+
+ if (verbose) {
+ apr_file_printf(errfile, "DBM Format: %s" NL, format);
+ }
+
+ if (!strcmp(input, "-")) {
+ rv = apr_file_open_stdin(&infile, pool);
+ }
+ else {
+ rv = apr_file_open(&infile, input, APR_READ|APR_BUFFERED,
+ APR_OS_DEFAULT, pool);
+ }
+
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile,
+ "Error: Cannot open input file '%s': (%d) %pm" NL NL,
+ input, rv, &rv);
+ return 1;
+ }
+
+ if (verbose) {
+ apr_file_printf(errfile, "Input File: %s" NL, input);
+ }
+
+ rv = apr_dbm_open_ex(&outdbm, format, output, APR_DBM_RWCREATE,
+ APR_OS_DEFAULT, pool);
+
+ if (APR_STATUS_IS_ENOTIMPL(rv)) {
+ apr_file_printf(errfile,
+ "Error: The requested DBM Format '%s' is not available." NL NL,
+ format);
+ return 1;
+ }
+
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile,
+ "Error: Cannot open output DBM '%s': (%d) %pm" NL NL,
+ output, rv, &rv);
+ return 1;
+ }
+
+ if (verbose) {
+ apr_file_printf(errfile, "DBM File: %s" NL, output);
+ }
+
+ rv = to_dbm(outdbm, infile, pool);
+
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile,
+ "Error: Converting to DBM: (%d) %pm" NL NL,
+ rv, &rv);
+ return 1;
+ }
+
+ apr_dbm_close(outdbm);
+
+ if (verbose) {
+ apr_file_printf(errfile, "Conversion Complete." NL);
+ }
+
+ return 0;
+}
+
diff --git a/support/httxt2dbm.dep b/support/httxt2dbm.dep
new file mode 100644
index 0000000..b546ab4
--- /dev/null
+++ b/support/httxt2dbm.dep
@@ -0,0 +1,26 @@
+# Microsoft Developer Studio Generated Dependency File, included by httxt2dbm.mak
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
+
+.\httxt2dbm.c : \
+ "..\srclib\apr-util\include\apr_dbm.h"\
+ "..\srclib\apr-util\include\apu.h"\
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
diff --git a/support/httxt2dbm.dsp b/support/httxt2dbm.dsp
new file mode 100644
index 0000000..94ed525
--- /dev/null
+++ b/support/httxt2dbm.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="httxt2dbm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=httxt2dbm - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "httxt2dbm.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "httxt2dbm.mak" CFG="httxt2dbm - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "httxt2dbm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "httxt2dbm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "httxt2dbm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/httxt2dbm_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\httxt2dbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/httxt2dbm_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\httxt2dbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "httxt2dbm - Win32 Release"
+# Name "httxt2dbm - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\httxt2dbm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/httxt2dbm.mak b/support/httxt2dbm.mak
new file mode 100644
index 0000000..615f0e9
--- /dev/null
+++ b/support/httxt2dbm.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on httxt2dbm.dsp
+!IF "$(CFG)" == ""
+CFG=httxt2dbm - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to httxt2dbm - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "httxt2dbm - Win32 Release" && "$(CFG)" != "httxt2dbm - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "httxt2dbm.mak" CFG="httxt2dbm - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "httxt2dbm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "httxt2dbm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "httxt2dbm - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\httxt2dbm.obj"
+ -@erase "$(INTDIR)\httxt2dbm.res"
+ -@erase "$(INTDIR)\httxt2dbm_src.idb"
+ -@erase "$(INTDIR)\httxt2dbm_src.pdb"
+ -@erase "$(OUTDIR)\httxt2dbm.exe"
+ -@erase "$(OUTDIR)\httxt2dbm.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\httxt2dbm_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\httxt2dbm.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\httxt2dbm.pdb" /debug /out:"$(OUTDIR)\httxt2dbm.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\httxt2dbm.obj" \
+ "$(INTDIR)\httxt2dbm.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\httxt2dbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\httxt2dbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\httxt2dbm.exe"
+ if exist .\Release\httxt2dbm.exe.manifest mt.exe -manifest .\Release\httxt2dbm.exe.manifest -outputresource:.\Release\httxt2dbm.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\httxt2dbm.obj"
+ -@erase "$(INTDIR)\httxt2dbm.res"
+ -@erase "$(INTDIR)\httxt2dbm_src.idb"
+ -@erase "$(INTDIR)\httxt2dbm_src.pdb"
+ -@erase "$(OUTDIR)\httxt2dbm.exe"
+ -@erase "$(OUTDIR)\httxt2dbm.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\httxt2dbm_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\httxt2dbm.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\httxt2dbm.pdb" /debug /out:"$(OUTDIR)\httxt2dbm.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\httxt2dbm.obj" \
+ "$(INTDIR)\httxt2dbm.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\httxt2dbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\httxt2dbm.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\httxt2dbm.exe"
+ if exist .\Debug\httxt2dbm.exe.manifest mt.exe -manifest .\Debug\httxt2dbm.exe.manifest -outputresource:.\Debug\httxt2dbm.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("httxt2dbm.dep")
+!INCLUDE "httxt2dbm.dep"
+!ELSE
+!MESSAGE Warning: cannot find "httxt2dbm.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "httxt2dbm - Win32 Release" || "$(CFG)" == "httxt2dbm - Win32 Debug"
+
+!IF "$(CFG)" == "httxt2dbm - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "httxt2dbm - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "httxt2dbm - Win32 Release"
+
+
+"$(INTDIR)\httxt2dbm.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug"
+
+
+"$(INTDIR)\httxt2dbm.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\httxt2dbm.c
+
+"$(INTDIR)\httxt2dbm.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/support/list_hooks.pl b/support/list_hooks.pl
new file mode 100755
index 0000000..7a6c933
--- /dev/null
+++ b/support/list_hooks.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -w
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+
+use Carp;
+
+my $path=shift || '.';
+
+findInDir($path);
+
+foreach my $hook (sort keys %::Hooks) {
+ my $h=$::Hooks{$hook};
+ for my $x (qw(declared implemented type args)) {
+ print "$hook datum '$x' missing\n" if !exists $h->{$x};
+ }
+ print "$hook\n";
+ print " declared in $h->{declared}\n" if defined $h->{declared};
+ print " implemented in $h->{implemented}\n" if defined $h->{implemented};
+ print " type is $h->{type}\n" if defined $h->{type};
+ print " $h->{ret} $hook($h->{args})\n" if defined $h->{args};
+ print "\n";
+}
+
+sub findInDir {
+ my $path=shift;
+
+ local(*D);
+ opendir(D,$path) || croak "Can't open $path: $!";
+ while(my $f=readdir D) {
+ next if $f=~/^\./;
+ my $file="$path/$f";
+
+ if(-d $file) {
+ findInDir($file);
+ next;
+ }
+ next if $file !~ /\.[ch]$/;
+
+ scanFile($file);
+ }
+ closedir D;
+}
+
+sub scanFile {
+ my $file=shift;
+
+# print "scanning $file\n";
+
+ open(F,$file) || croak "Can't open $file: $!";
+ while(<F>) {
+ next if /\#define/;
+ next if /\@deffunc/;
+ if(/AP_DECLARE_HOOK\s*\(/) {
+ my($ret,$name,$args);
+ while(!(($ret,$name,$args)=
+ /AP_DECLARE_HOOK\s*\(\s*([^,]+)\s*,\s*([^,\s]+)\s*,\s*\((.*?)\)\)/s)) {
+ chomp;
+ # swallow subsequent lines if needed to get all the required info
+ my $l=<F>;
+ return unless defined $l;
+ $l=~s/^\s*/ /;
+ $_.=$l;
+ }
+ $ret=~s/\s*$//;
+ $args=~s/^\s*//; $args=~s/\s*$//;
+# print "found $ret $name($args) in $file\n";
+
+ croak "$name declared twice! ($_)"
+ if exists $::Hooks{$name}->{declared};
+ $::Hooks{$name}->{declared}=$file;
+ $::Hooks{$name}->{ret}=$ret;
+ $::Hooks{$name}->{args}=$args;
+ }
+ if(/AP_IMPLEMENT_HOOK_()(VOID)\(([^,\s]+)/
+ || /AP_IMPLEMENT(_OPTIONAL|)_HOOK_(.*?)\([^,]+?\s*,\s*([^,\s]+)/) {
+ my($type,$name)=($1 ? "OPTIONAL $2" : $2,$3);
+
+# print "found $name $type in $file\n";
+
+ croak "$name implemented twice ($::Hooks{$name}->{implemented} and $file) ($_)"
+ if exists $::Hooks{$name}->{implemented};
+ $::Hooks{$name}->{implemented}=$file;
+ $::Hooks{$name}->{type}=$type;
+ }
+ }
+}
diff --git a/support/log_server_status.in b/support/log_server_status.in
new file mode 100644
index 0000000..ba08d7e
--- /dev/null
+++ b/support/log_server_status.in
@@ -0,0 +1,76 @@
+#!@perlbin@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# Log Server Status
+# Mark J Cox, UK Web Ltd 1996, mark ukweb.com
+#
+# This script is designed to be run at a frequent interval by something
+# like cron. It connects to the server and downloads the status
+# information. It reformats the information to a single line and logs
+# it to a file. Make sure the directory $wherelog is writable by the
+# user who runs this script.
+#
+use IO::Socket;
+use strict;
+use warnings;
+
+my $wherelog = "@exp_logfiledir@/"; # Logs will be like "@exp_logfiledir@/19960312"
+my $server = "localhost"; # Name of server, could be "www.foo.com"
+my $port = "@PORT@"; # Port on server
+my $request = "/server-status/?auto"; # Request to send
+
+my @ltime = localtime(time);
+
+my $day =
+ $ltime[5] + 1900
+ . sprintf( "%02d", $ltime[4] + 1 )
+ . sprintf( "%02d", $ltime[3] );
+
+my $time =
+ sprintf( "%02d", $ltime[2] )
+ . sprintf( "%02d", $ltime[1] )
+ . sprintf( "%02d", $ltime[0] );
+
+open(OUT,">>$wherelog$day");
+
+my $socket = new IO::Socket::INET(
+ PeerAddr => $server,
+ PeerPort => $port,
+ Proto => "tcp",
+ Type => SOCK_STREAM
+ )
+ or do {
+ print OUT "$time:-1:-1:-1:-1:$@\n";
+ close OUT;
+ die "Couldn't connect to $server:$port : $@\n";
+ };
+$| = 1;
+
+print $socket
+ "GET $request HTTP/1.1\r\nHost: $server\r\nConnection: close\r\n\r\n\r\n";
+
+my ( $requests, $idle, $number, $cpu );
+while (<$socket>) {
+ $requests = $1 if (m|^BusyWorkers:\ (\S+)|);
+ $idle = $1 if (m|^IdleWorkers:\ (\S+)|);
+ $number = $1 if (m|sses:\ (\S+)|);
+ $cpu = $1 if (m|^CPULoad:\ (\S+)|);
+}
+print OUT "$time:$requests:$idle:$number:$cpu\n";
+close OUT;
+
diff --git a/support/logresolve.c b/support/logresolve.c
new file mode 100644
index 0000000..1cab753
--- /dev/null
+++ b/support/logresolve.c
@@ -0,0 +1,329 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * logresolve 2.0
+ *
+ * Tom Rathborne - tomr uunet.ca - http://www.uunet.ca/~tomr/
+ * UUNET Canada, April 16, 1995
+ *
+ * Rewritten by David Robinson. (drtr ast.cam.ac.uk)
+ * Rewritten again, and ported to APR by Colm MacCarthaigh
+ *
+ * Usage: logresolve [-s filename] [-c] < access_log > new_log
+ *
+ * Arguments:
+ * -s filename name of a file to record statistics
+ * -c check the DNS for a matching A record for the host.
+ *
+ * Notes: (For historical interest)
+ *
+ * To generate meaningful statistics from an HTTPD log file, it's good
+ * to have the domain name of each machine that accessed your site, but
+ * doing this on the fly can slow HTTPD down.
+ *
+ * Compiling NCSA HTTPD with the -DMINIMAL_DNS flag turns IP#->hostname
+ * resolution off. Before running your stats program, just run your log
+ * file through this program (logresolve) and all of your IP numbers will
+ * be resolved into hostnames (where possible).
+ *
+ * logresolve takes an HTTPD access log (in the COMMON log file format,
+ * or any other format that has the IP number/domain name as the first
+ * field for that matter), and outputs the same file with all of the
+ * domain names looked up. Where no domain name can be found, the IP
+ * number is left in.
+ *
+ * To minimize impact on your nameserver, logresolve has its very own
+ * internal hash-table cache. This means that each IP number will only
+ * be looked up the first time it is found in the log file.
+ *
+ * The -c option causes logresolve to apply the same check as httpd
+ * compiled with -DMAXIMUM_DNS; after finding the hostname from the IP
+ * address, it looks up the IP addresses for the hostname and checks
+ * that one of these matches the original address.
+ */
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_hash.h"
+#include "apr_getopt.h"
+#include "apr_strings.h"
+#include "apr_file_io.h"
+#include "apr_network_io.h"
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#define READ_BUF_SIZE 128*1024
+#define WRITE_BUF_SIZE 128*1024
+#define LINE_BUF_SIZE 128*1024
+
+static apr_file_t *errfile;
+static const char *shortname = "logresolve";
+static apr_hash_t *cache;
+
+/* Statistics */
+static int cachehits = 0;
+static int cachesize = 0;
+static int entries = 0;
+static int resolves = 0;
+static int withname = 0;
+static int doublefailed = 0;
+static int noreverse = 0;
+
+/*
+ * prints various statistics to output
+ */
+#define NL APR_EOL_STR
+static void print_statistics (apr_file_t *output)
+{
+ apr_file_printf(output, "logresolve Statistics:" NL);
+ apr_file_printf(output, "Entries: %d" NL, entries);
+ apr_file_printf(output, " With name : %d" NL, withname);
+ apr_file_printf(output, " Resolves : %d" NL, resolves);
+
+ if (noreverse) {
+ apr_file_printf(output, " - No reverse : %d" NL,
+ noreverse);
+ }
+
+ if (doublefailed) {
+ apr_file_printf(output, " - Double lookup failed : %d" NL,
+ doublefailed);
+ }
+
+ apr_file_printf(output, "Cache hits : %d" NL, cachehits);
+ apr_file_printf(output, "Cache size : %d" NL, cachesize);
+}
+
+/*
+ * usage info
+ */
+static void usage(void)
+{
+ apr_file_printf(errfile,
+ "%s -- Resolve IP-addresses to hostnames in Apache log files." NL
+ "Usage: %s [-s STATFILE] [-c]" NL
+ NL
+ "Options:" NL
+ " -s Record statistics to STATFILE when finished." NL
+ NL
+ " -c Perform double lookups when resolving IP addresses." NL,
+ shortname, shortname);
+ exit(1);
+}
+#undef NL
+
+int main(int argc, const char * const argv[])
+{
+ apr_file_t * outfile;
+ apr_file_t * infile;
+ apr_getopt_t * o;
+ apr_pool_t * pool;
+ apr_pool_t *pline;
+ apr_status_t status;
+ const char * arg;
+ char * stats = NULL;
+ char * inbuffer;
+ char * outbuffer;
+ char * line;
+ int doublelookups = 0;
+
+ if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) {
+ return 1;
+ }
+ atexit(apr_terminate);
+
+ if (argc) {
+ shortname = apr_filepath_name_get(argv[0]);
+ }
+
+ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
+ return 1;
+ }
+ apr_file_open_stderr(&errfile, pool);
+ apr_getopt_init(&o, pool, argc, argv);
+
+ while (1) {
+ char opt;
+ status = apr_getopt(o, "s:c", &opt, &arg);
+ if (status == APR_EOF) {
+ break;
+ }
+ else if (status != APR_SUCCESS) {
+ usage();
+ }
+ else {
+ switch (opt) {
+ case 'c':
+ if (doublelookups) {
+ usage();
+ }
+ doublelookups = 1;
+ break;
+ case 's':
+ if (stats) {
+ usage();
+ }
+ stats = apr_pstrdup(pool, arg);
+ break;
+ } /* switch */
+ } /* else */
+ } /* while */
+
+ apr_file_open_stdout(&outfile, pool);
+ apr_file_open_stdin(&infile, pool);
+
+ /* Allocate two new 10k file buffers */
+ if ( (outbuffer = apr_palloc(pool, WRITE_BUF_SIZE)) == NULL
+ || (inbuffer = apr_palloc(pool, READ_BUF_SIZE)) == NULL
+ || (line = apr_palloc(pool, LINE_BUF_SIZE)) == NULL) {
+ return 1;
+ }
+
+ /* Set the buffers */
+ apr_file_buffer_set(infile, inbuffer, READ_BUF_SIZE);
+ apr_file_buffer_set(outfile, outbuffer, WRITE_BUF_SIZE);
+
+ cache = apr_hash_make(pool);
+ if (apr_pool_create(&pline, pool) != APR_SUCCESS) {
+ return 1;
+ }
+
+ while (apr_file_gets(line, LINE_BUF_SIZE, infile) == APR_SUCCESS) {
+ char *hostname;
+ char *space;
+ apr_sockaddr_t *ip;
+ apr_sockaddr_t *ipdouble;
+ char dummy[] = " " APR_EOL_STR;
+
+ if (line[0] == '\0') {
+ continue;
+ }
+
+ /* Count our log entries */
+ entries++;
+
+ /* Check if this could even be an IP address */
+ if (!apr_isxdigit(line[0]) && line[0] != ':') {
+ withname++;
+ apr_file_puts(line, outfile);
+ continue;
+ }
+
+ /* Terminate the line at the next space */
+ if ((space = strchr(line, ' ')) != NULL) {
+ *space = '\0';
+ }
+ else {
+ space = dummy;
+ }
+
+ /* See if we have it in our cache */
+ hostname = (char *) apr_hash_get(cache, line, APR_HASH_KEY_STRING);
+ if (hostname) {
+ apr_file_printf(outfile, "%s %s", hostname, space + 1);
+ cachehits++;
+ continue;
+ }
+
+ /* Parse the IP address */
+ status = apr_sockaddr_info_get(&ip, line, APR_UNSPEC, 0, 0, pline);
+ if (status != APR_SUCCESS) {
+ /* Not an IP address */
+ withname++;
+ *space = ' ';
+ apr_file_puts(line, outfile);
+ continue;
+ }
+
+ /* This does not make much sense, but historically "resolves" means
+ * "parsed as an IP address". It does not mean we actually resolved
+ * the IP address into a hostname.
+ */
+ resolves++;
+
+ /* From here on our we cache each result, even if it was not
+ * successful
+ */
+ cachesize++;
+
+ /* Try and perform a reverse lookup */
+ status = apr_getnameinfo(&hostname, ip, 0) != APR_SUCCESS;
+ if (status || hostname == NULL) {
+ /* Could not perform a reverse lookup */
+ *space = ' ';
+ apr_file_puts(line, outfile);
+ noreverse++;
+
+ /* Add to cache */
+ *space = '\0';
+ apr_hash_set(cache, line, APR_HASH_KEY_STRING,
+ apr_pstrdup(apr_hash_pool_get(cache), line));
+ continue;
+ }
+
+ /* Perform a double lookup */
+ if (doublelookups) {
+ /* Do a forward lookup on our hostname, and see if that matches our
+ * original IP address.
+ */
+ status = apr_sockaddr_info_get(&ipdouble, hostname, ip->family, 0,
+ 0, pline);
+ if (status != APR_SUCCESS ||
+ memcmp(ipdouble->ipaddr_ptr, ip->ipaddr_ptr, ip->ipaddr_len)) {
+ /* Double-lookup failed */
+ *space = ' ';
+ apr_file_puts(line, outfile);
+ doublefailed++;
+
+ /* Add to cache */
+ *space = '\0';
+ apr_hash_set(cache, line, APR_HASH_KEY_STRING,
+ apr_pstrdup(apr_hash_pool_get(cache), line));
+ continue;
+ }
+ }
+
+ /* Output the resolved name */
+ apr_file_printf(outfile, "%s %s", hostname, space + 1);
+
+ /* Store it in the cache */
+ apr_hash_set(cache, line, APR_HASH_KEY_STRING,
+ apr_pstrdup(apr_hash_pool_get(cache), hostname));
+
+ apr_pool_clear(pline);
+ }
+
+ /* Flush any remaining output */
+ apr_file_flush(outfile);
+
+ if (stats) {
+ apr_file_t *statsfile;
+ if (apr_file_open(&statsfile, stats,
+ APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE,
+ APR_OS_DEFAULT, pool) != APR_SUCCESS) {
+ apr_file_printf(errfile, "%s: Could not open %s for writing.",
+ shortname, stats);
+ return 1;
+ }
+ print_statistics(statsfile);
+ apr_file_close(statsfile);
+ }
+
+ return 0;
+}
diff --git a/support/logresolve.dep b/support/logresolve.dep
new file mode 100644
index 0000000..7b6c07f
--- /dev/null
+++ b/support/logresolve.dep
@@ -0,0 +1,26 @@
+# Microsoft Developer Studio Generated Dependency File, included by logresolve.mak
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
+
+.\logresolve.c : \
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_hash.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_network_io.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
diff --git a/support/logresolve.dsp b/support/logresolve.dsp
new file mode 100644
index 0000000..648daac
--- /dev/null
+++ b/support/logresolve.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="logresolve" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=logresolve - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "logresolve.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "logresolve.mak" CFG="logresolve - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "logresolve - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "logresolve - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "logresolve - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/logresolve_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/logresolve.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\logresolve.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "logresolve - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/logresolve_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/logresolve.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\logresolve.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "logresolve - Win32 Release"
+# Name "logresolve - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\logresolve.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/logresolve.mak b/support/logresolve.mak
new file mode 100644
index 0000000..6e54624
--- /dev/null
+++ b/support/logresolve.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on logresolve.dsp
+!IF "$(CFG)" == ""
+CFG=logresolve - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to logresolve - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "logresolve - Win32 Release" && "$(CFG)" != "logresolve - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "logresolve.mak" CFG="logresolve - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "logresolve - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "logresolve - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "logresolve - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\logresolve.obj"
+ -@erase "$(INTDIR)\logresolve.res"
+ -@erase "$(INTDIR)\logresolve_src.idb"
+ -@erase "$(INTDIR)\logresolve_src.pdb"
+ -@erase "$(OUTDIR)\logresolve.exe"
+ -@erase "$(OUTDIR)\logresolve.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\logresolve_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\logresolve.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\logresolve.pdb" /debug /out:"$(OUTDIR)\logresolve.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\logresolve.obj" \
+ "$(INTDIR)\logresolve.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\logresolve.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\logresolve.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\logresolve.exe"
+ if exist .\Release\logresolve.exe.manifest mt.exe -manifest .\Release\logresolve.exe.manifest -outputresource:.\Release\logresolve.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "logresolve - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\logresolve.obj"
+ -@erase "$(INTDIR)\logresolve.res"
+ -@erase "$(INTDIR)\logresolve_src.idb"
+ -@erase "$(INTDIR)\logresolve_src.pdb"
+ -@erase "$(OUTDIR)\logresolve.exe"
+ -@erase "$(OUTDIR)\logresolve.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\logresolve_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\logresolve.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\logresolve.pdb" /debug /out:"$(OUTDIR)\logresolve.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\logresolve.obj" \
+ "$(INTDIR)\logresolve.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\logresolve.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\logresolve.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\logresolve.exe"
+ if exist .\Debug\logresolve.exe.manifest mt.exe -manifest .\Debug\logresolve.exe.manifest -outputresource:.\Debug\logresolve.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("logresolve.dep")
+!INCLUDE "logresolve.dep"
+!ELSE
+!MESSAGE Warning: cannot find "logresolve.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "logresolve - Win32 Release" || "$(CFG)" == "logresolve - Win32 Debug"
+
+!IF "$(CFG)" == "logresolve - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "logresolve - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "logresolve - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "logresolve - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "logresolve - Win32 Release"
+
+
+"$(INTDIR)\logresolve.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "logresolve - Win32 Debug"
+
+
+"$(INTDIR)\logresolve.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\logresolve.c
+
+"$(INTDIR)\logresolve.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/support/logresolve.pl.in b/support/logresolve.pl.in
new file mode 100644
index 0000000..2cd212d
--- /dev/null
+++ b/support/logresolve.pl.in
@@ -0,0 +1,225 @@
+#!@perlbin@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# logresolve.pl
+#
+# v 1.2 by robh imdb.com
+#
+# usage: logresolve.pl <infile >outfile
+#
+# input = Apache/NCSA/.. logfile with IP numbers at start of lines
+# output = same logfile with IP addresses resolved to hostnames where
+# name lookups succeeded.
+#
+# this differs from the C based 'logresolve' in that this script
+# spawns a number ($CHILDREN) of subprocesses to resolve addresses
+# concurrently and sets a short timeout ($TIMEOUT) for each lookup in
+# order to keep things moving quickly.
+#
+# the parent process handles caching of IP->hostnames using a Perl hash
+# it also avoids sending the same IP to multiple child processes to be
+# resolved multiple times concurrently.
+#
+# Depending on the settings of $CHILDREN and $TIMEOUT you should see
+# significant reductions in the overall time taken to resolve your
+# logfiles. With $CHILDREN=40 and $TIMEOUT=5 I've seen 200,000 - 300,000
+# logfile lines processed per hour compared to ~45,000 per hour
+# with 'logresolve'.
+#
+# I haven't yet seen any noticeable reduction in the percentage of IPs
+# that fail to get resolved. Your mileage will no doubt vary. 5s is long
+# enough to wait IMO.
+#
+# Known to work with FreeBSD 2.2
+# Known to have problems with Solaris
+#
+# 980417 - use 'sockaddr_un' for bind/connect to make the script work
+# with linux. Fix from Luuk de Boer <luuk_de_boer pi.net>
+
+require 5.004;
+
+$|=1;
+
+use FileHandle;
+use Socket;
+
+use strict;
+no strict 'refs';
+
+use vars qw($PROTOCOL);
+$PROTOCOL = 0;
+
+my $CHILDREN = 40;
+my $TIMEOUT = 5;
+
+my $filename;
+my %hash = ();
+my $parent = $$;
+
+my @children = ();
+for (my $child = 1; $child <=$CHILDREN; $child++) {
+ my $f = fork();
+ if (!$f) {
+ $filename = "./.socket.$parent.$child";
+ if (-e $filename) { unlink($filename) || warn "$filename .. $!\n";}
+ &child($child);
+ exit(0);
+ }
+ push(@children, $f);
+}
+
+&parent;
+&cleanup;
+
+## remove all temporary files before shutting down
+sub cleanup {
+ # die kiddies, die
+ kill(15, @children);
+ for (my $child = 1; $child <=$CHILDREN; $child++) {
+ if (-e "./.socket.$parent.$child") {
+ unlink("./.socket.$parent.$child")
+ || warn ".socket.$parent.$child $!";
+ }
+ }
+}
+
+sub parent {
+ # Trap some possible signals to trigger temp file cleanup
+ $SIG{'KILL'} = $SIG{'INT'} = $SIG{'PIPE'} = \&cleanup;
+
+ my %CHILDSOCK;
+ my $filename;
+
+ ## fork child processes. Each child will create a socket connection
+ ## to this parent and use an unique temp filename to do so.
+ for (my $child = 1; $child <=$CHILDREN; $child++) {
+ $CHILDSOCK{$child}= FileHandle->new;
+
+ if (!socket($CHILDSOCK{$child}, AF_UNIX, SOCK_STREAM, $PROTOCOL)) {
+ warn "parent socket to child failed $!";
+ }
+ $filename = "./.socket.$parent.$child";
+ my $response;
+ do {
+ $response = connect($CHILDSOCK{$child}, sockaddr_un($filename));
+ if ($response != 1) {
+ sleep(1);
+ }
+ } while ($response != 1);
+ $CHILDSOCK{$child}->autoflush;
+ }
+ ## All child processes should now be ready or at worst warming up
+
+ my (@buffer, $child, $ip, $rest, $hostname, $response);
+ ## read the logfile lines from STDIN
+ while(<STDIN>) {
+ @buffer = (); # empty the logfile line buffer array.
+ $child = 1; # children are numbered 1..N, start with #1
+
+ # while we have a child to talk to and data to give it..
+ do {
+ push(@buffer, $_); # buffer the line
+ ($ip, $rest) = split(/ /, $_, 2); # separate IP form rest
+
+ unless ($hash{$ip}) { # resolve if unseen IP
+ $CHILDSOCK{$child}->print("$ip\n"); # pass IP to next child
+ $hash{$ip} = $ip; # don't look it up again.
+ $child++;
+ }
+ } while (($child < ($CHILDREN-1)) and ($_ = <STDIN>));
+
+ ## now poll each child for a response
+ while (--$child > 0) {
+ $response = $CHILDSOCK{$child}->getline;
+ chomp($response);
+ # child sends us back both the IP and HOSTNAME, no need for us
+ # to remember what child received any given IP, and no worries
+ # what order we talk to the children
+ ($ip, $hostname) = split(/\|/, $response, 2);
+ $hash{$ip} = $hostname;
+ }
+
+ # resolve all the logfiles lines held in the log buffer array..
+ for (my $line = 0; $line <=$#buffer; $line++) {
+ # get next buffered line
+ ($ip, $rest) = split(/ /, $buffer[$line], 2);
+ # separate IP from rest and replace with cached hostname
+ printf STDOUT ("%s %s", $hash{$ip}, $rest);
+ }
+ }
+}
+
+########################################
+
+sub child {
+ # arg = numeric ID - how the parent refers to me
+ my $me = shift;
+
+ # add trap for alarm signals.
+ $SIG{'ALRM'} = sub { die "alarmed"; };
+
+ # create a socket to communicate with parent
+ socket(INBOUND, AF_UNIX, SOCK_STREAM, $PROTOCOL)
+ || die "Error with Socket: !$\n";
+ $filename = "./.socket.$parent.$me";
+ bind(INBOUND, sockaddr_un($filename))
+ || die "Error Binding $filename: $!\n";
+ listen(INBOUND, 5) || die "Error Listening: $!\n";
+
+ my ($ip, $send_back);
+ my $talk = FileHandle->new;
+
+ # accept a connection from the parent process. We only ever have
+ # have one connection where we exchange 1 line of info with the
+ # parent.. 1 line in (IP address), 1 line out (IP + hostname).
+ accept($talk, INBOUND) || die "Error Accepting: $!\n";
+ # disable I/O buffering just in case
+ $talk->autoflush;
+ # while the parent keeps sending data, we keep responding..
+ while(($ip = $talk->getline)) {
+ chomp($ip);
+ # resolve the IP if time permits and send back what we found..
+ $send_back = sprintf("%s|%s", $ip, &nslookup($ip));
+ $talk->print($send_back."\n");
+ }
+}
+
+# perform a time restricted hostname lookup.
+sub nslookup {
+ # get the IP as an arg
+ my $ip = shift;
+ my $hostname = undef;
+
+ # do the hostname lookup inside an eval. The eval will use the
+ # already configured SIGnal handler and drop out of the {} block
+ # regardless of whether the alarm occurred or not.
+ eval {
+ alarm($TIMEOUT);
+ $hostname = gethostbyaddr(gethostbyname($ip), AF_INET);
+ alarm(0);
+ };
+ if ($@ =~ /alarm/) {
+ # useful for debugging perhaps..
+ # print "alarming, isn't it? ($ip)";
+ }
+
+ # return the hostname or the IP address itself if there is no hostname
+ $hostname ne "" ? $hostname : $ip;
+}
+
+
diff --git a/support/passwd_common.c b/support/passwd_common.c
new file mode 100644
index 0000000..664e509
--- /dev/null
+++ b/support/passwd_common.c
@@ -0,0 +1,344 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "passwd_common.h"
+#include "apr_strings.h"
+#include "apr_errno.h"
+
+#if APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#include "apr_md5.h"
+#include "apr_sha1.h"
+
+#if APR_HAVE_TIME_H
+#include <time.h>
+#endif
+#if APR_HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if APR_HAVE_STRING_H
+#include <string.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_IO_H
+#include <io.h>
+#endif
+
+#ifdef _MSC_VER
+#define write _write
+#endif
+
+apr_file_t *errfile;
+
+int abort_on_oom(int rc)
+{
+ const char *buf = "Error: out of memory\n";
+ int written, count = strlen(buf);
+ do {
+ written = write(STDERR_FILENO, buf, count);
+ if (written == count)
+ break;
+ if (written > 0) {
+ buf += written;
+ count -= written;
+ }
+ } while (written >= 0 || errno == EINTR);
+ abort();
+ /* NOTREACHED */
+ return 0;
+}
+
+static int generate_salt(char *s, size_t size, const char **errstr,
+ apr_pool_t *pool)
+{
+ unsigned char rnd[32];
+ static const char itoa64[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ apr_size_t n;
+ unsigned int val = 0, bits = 0;
+ apr_status_t rv;
+
+ n = (size * 6 + 7)/8;
+ if (n > sizeof(rnd)) {
+ apr_file_printf(errfile, "generate_salt(): BUG: Buffer too small");
+ abort();
+ }
+ rv = apr_generate_random_bytes(rnd, n);
+ if (rv) {
+ *errstr = apr_psprintf(pool, "Unable to generate random bytes: %pm",
+ &rv);
+ return ERR_RANDOM;
+ }
+ n = 0;
+ while (size > 0) {
+ if (bits < 6) {
+ val |= (rnd[n++] << bits);
+ bits += 8;
+ }
+ *s++ = itoa64[val & 0x3f];
+ size--;
+ val >>= 6;
+ bits -= 6;
+ }
+ *s = '\0';
+ return 0;
+}
+
+void putline(apr_file_t *f, const char *l)
+{
+ apr_status_t rv;
+ if (f == NULL)
+ return;
+ rv = apr_file_puts(l, f);
+ if (rv != APR_SUCCESS) {
+ apr_file_printf(errfile, "Error writing temp file: %pm", &rv);
+ apr_file_close(f);
+ exit(ERR_FILEPERM);
+ }
+}
+
+int get_password(struct passwd_ctx *ctx)
+{
+ char buf[MAX_STRING_LEN + 1];
+ if (ctx->passwd_src == PW_STDIN) {
+ apr_file_t *file_stdin;
+ apr_size_t nread;
+ if (apr_file_open_stdin(&file_stdin, ctx->pool) != APR_SUCCESS) {
+ ctx->errstr = "Unable to read from stdin.";
+ return ERR_GENERAL;
+ }
+ if (apr_file_read_full(file_stdin, buf, sizeof(buf) - 1,
+ &nread) != APR_EOF
+ || nread == sizeof(buf) - 1) {
+ goto err_too_long;
+ }
+ buf[nread] = '\0';
+ if (nread >= 1 && buf[nread-1] == '\n') {
+ buf[nread-1] = '\0';
+ if (nread >= 2 && buf[nread-2] == '\r')
+ buf[nread-2] = '\0';
+ }
+ apr_file_close(file_stdin);
+ ctx->passwd = apr_pstrdup(ctx->pool, buf);
+ }
+ else if (ctx->passwd_src == PW_PROMPT_VERIFY) {
+ apr_size_t bufsize = sizeof(buf);
+ if (apr_password_get("Enter password: ", buf, &bufsize) != 0)
+ goto err_too_long;
+ ctx->passwd = apr_pstrdup(ctx->pool, buf);
+ }
+ else {
+ apr_size_t bufsize = sizeof(buf);
+ if (apr_password_get("New password: ", buf, &bufsize) != 0)
+ goto err_too_long;
+ ctx->passwd = apr_pstrdup(ctx->pool, buf);
+ bufsize = sizeof(buf);
+ buf[0] = '\0';
+ apr_password_get("Re-type new password: ", buf, &bufsize);
+ if (strcmp(ctx->passwd, buf) != 0) {
+ ctx->errstr = "password verification error";
+ memset(ctx->passwd, '\0', strlen(ctx->passwd));
+ memset(buf, '\0', sizeof(buf));
+ return ERR_PWMISMATCH;
+ }
+ }
+ memset(buf, '\0', sizeof(buf));
+ return 0;
+
+err_too_long:
+ ctx->errstr = apr_psprintf(ctx->pool,
+ "password too long (>%" APR_SIZE_T_FMT ")",
+ sizeof(buf) - 1);
+ return ERR_OVERFLOW;
+}
+
+/*
+ * Make a password record from the given information. A zero return
+ * indicates success; on failure, ctx->errstr points to the error message.
+ */
+int mkhash(struct passwd_ctx *ctx)
+{
+ char *pw;
+ char salt[16];
+ apr_status_t rv;
+ int ret = 0;
+#if CRYPT_ALGO_SUPPORTED
+ char *cbuf;
+#endif
+
+ if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) {
+ apr_file_printf(errfile,
+ "Warning: Ignoring -C argument for this algorithm." NL);
+ }
+
+ if (ctx->passwd == NULL) {
+ if ((ret = get_password(ctx)) != 0)
+ return ret;
+ }
+ pw = ctx->passwd;
+
+ switch (ctx->alg) {
+ case ALG_APSHA:
+ /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */
+ apr_sha1_base64(pw, strlen(pw), ctx->out);
+ break;
+
+ case ALG_APMD5:
+ ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
+ if (ret != 0)
+ break;
+ rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len);
+ if (rv != APR_SUCCESS) {
+ ctx->errstr = apr_psprintf(ctx->pool,
+ "could not encode password: %pm", &rv);
+ ret = ERR_GENERAL;
+ }
+ break;
+
+ case ALG_PLAIN:
+ /* XXX this len limitation is not in sync with any HTTPd len. */
+ apr_cpystrn(ctx->out, pw, ctx->out_len);
+ break;
+
+#if CRYPT_ALGO_SUPPORTED
+ case ALG_CRYPT:
+ ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
+ if (ret != 0)
+ break;
+ cbuf = crypt(pw, salt);
+ if (cbuf == NULL) {
+ rv = APR_FROM_OS_ERROR(errno);
+ ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv);
+ ret = ERR_PWMISMATCH;
+ break;
+ }
+
+ apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1);
+ if (strlen(pw) > 8) {
+ char *truncpw = apr_pstrdup(ctx->pool, pw);
+ truncpw[8] = '\0';
+ if (!strcmp(ctx->out, crypt(truncpw, salt))) {
+ apr_file_printf(errfile, "Warning: Password truncated to 8 "
+ "characters by CRYPT algorithm." NL);
+ }
+ memset(truncpw, '\0', strlen(pw));
+ }
+ break;
+#endif /* CRYPT_ALGO_SUPPORTED */
+
+#if BCRYPT_ALGO_SUPPORTED
+ case ALG_BCRYPT:
+ rv = apr_generate_random_bytes((unsigned char*)salt, 16);
+ if (rv != APR_SUCCESS) {
+ ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random "
+ "bytes: %pm", &rv);
+ ret = ERR_RANDOM;
+ break;
+ }
+
+ if (ctx->cost == 0)
+ ctx->cost = BCRYPT_DEFAULT_COST;
+ rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16,
+ ctx->out, ctx->out_len);
+ if (rv != APR_SUCCESS) {
+ ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with "
+ "bcrypt: %pm", &rv);
+ ret = ERR_PWMISMATCH;
+ break;
+ }
+ break;
+#endif /* BCRYPT_ALGO_SUPPORTED */
+
+ default:
+ apr_file_printf(errfile, "mkhash(): BUG: invalid algorithm %d",
+ ctx->alg);
+ abort();
+ }
+ memset(pw, '\0', strlen(pw));
+ return ret;
+}
+
+int parse_common_options(struct passwd_ctx *ctx, char opt,
+ const char *opt_arg)
+{
+ switch (opt) {
+ case 'b':
+ ctx->passwd_src = PW_ARG;
+ break;
+ case 'i':
+ ctx->passwd_src = PW_STDIN;
+ break;
+ case 'm':
+ ctx->alg = ALG_APMD5;
+ break;
+ case 's':
+ ctx->alg = ALG_APSHA;
+ break;
+ case 'p':
+ ctx->alg = ALG_PLAIN;
+#if !PLAIN_ALGO_SUPPORTED
+ /* Backward compatible behavior: Just print a warning */
+ apr_file_printf(errfile,
+ "Warning: storing passwords as plain text might just "
+ "not work on this platform." NL);
+#endif
+ break;
+ case 'd':
+#if CRYPT_ALGO_SUPPORTED
+ ctx->alg = ALG_CRYPT;
+#else
+ /* Backward compatible behavior: Use MD5. OK since MD5 is more secure */
+ apr_file_printf(errfile,
+ "Warning: CRYPT algorithm not supported on this "
+ "platform." NL
+ "Automatically using MD5 format." NL);
+ ctx->alg = ALG_APMD5;
+#endif
+ break;
+ case 'B':
+#if BCRYPT_ALGO_SUPPORTED
+ ctx->alg = ALG_BCRYPT;
+#else
+ /* Don't fall back to something less secure */
+ ctx->errstr = "BCRYPT algorithm not supported on this platform";
+ return ERR_ALG_NOT_SUPP;
+#endif
+ break;
+ case 'C': {
+ char *endptr;
+ long num = strtol(opt_arg, &endptr, 10);
+ if (*endptr != '\0' || num <= 0) {
+ ctx->errstr = "argument to -C must be a positive integer";
+ return ERR_SYNTAX;
+ }
+ ctx->cost = num;
+ break;
+ }
+ default:
+ apr_file_printf(errfile,
+ "parse_common_options(): BUG: invalid option %c",
+ opt);
+ abort();
+ }
+ return 0;
+}
diff --git a/support/passwd_common.h b/support/passwd_common.h
new file mode 100644
index 0000000..660081e
--- /dev/null
+++ b/support/passwd_common.h
@@ -0,0 +1,128 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _PASSWD_COMMON_H
+#define _PASSWD_COMMON_H
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_errno.h"
+#include "apr_file_io.h"
+#include "apr_general.h"
+#include "apr_version.h"
+#if !APR_VERSION_AT_LEAST(2,0,0)
+#include "apu_version.h"
+#endif
+
+#define MAX_STRING_LEN 256
+
+#define ALG_PLAIN 0
+#define ALG_CRYPT 1
+#define ALG_APMD5 2
+#define ALG_APSHA 3
+#define ALG_BCRYPT 4
+
+#define BCRYPT_DEFAULT_COST 5
+
+#define ERR_FILEPERM 1
+#define ERR_SYNTAX 2
+#define ERR_PWMISMATCH 3
+#define ERR_INTERRUPTED 4
+#define ERR_OVERFLOW 5
+#define ERR_BADUSER 6
+#define ERR_INVALID 7
+#define ERR_RANDOM 8
+#define ERR_GENERAL 9
+#define ERR_ALG_NOT_SUPP 10
+
+#define NL APR_EOL_STR
+
+#if defined(WIN32) || defined(NETWARE)
+#define CRYPT_ALGO_SUPPORTED 0
+#define PLAIN_ALGO_SUPPORTED 1
+#else
+#define CRYPT_ALGO_SUPPORTED 1
+#define PLAIN_ALGO_SUPPORTED 0
+#endif
+
+#if APR_VERSION_AT_LEAST(2,0,0) || \
+ (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 5)
+#define BCRYPT_ALGO_SUPPORTED 1
+#else
+#define BCRYPT_ALGO_SUPPORTED 0
+#endif
+
+#if APR_CHARSET_EBCDIC
+#undef BCRYPT_ALGO_SUPPORTED
+#define BCRYPT_ALGO_SUPPORTED 0
+#endif
+
+/*
+ * Must be initialized with apr_file_open_stderr() before using any of the
+ * below functions.
+ */
+extern apr_file_t *errfile;
+
+struct passwd_ctx {
+ apr_pool_t *pool;
+ const char *errstr;
+ char *out;
+ apr_size_t out_len;
+ char *passwd;
+ int alg;
+ int cost;
+ enum {
+ PW_PROMPT = 0,
+ PW_ARG,
+ PW_STDIN,
+ PW_PROMPT_VERIFY,
+ } passwd_src;
+};
+
+
+/*
+ * To be used as apr_pool_abort_fn
+ */
+int abort_on_oom(int rc);
+
+/*
+ * Write a line to the file. On error, print a message and exit
+ */
+void putline(apr_file_t *f, const char *l);
+
+/*
+ * The following functions return zero on success; otherwise, one of
+ * the ERR_* codes is returned and an error message is stored in ctx->errstr.
+ */
+
+/*
+ * Parse the algorithm specific options.
+ */
+int parse_common_options(struct passwd_ctx *ctx, char opt, const char *opt_arg);
+
+/*
+ * Ask for password with verification.
+ */
+int get_password(struct passwd_ctx *ctx);
+
+/*
+ * Make a password record from the given information.
+ */
+int mkhash(struct passwd_ctx *ctx);
+
+#endif /* _PASSWD_COMMON_H */
+
diff --git a/support/phf_abuse_log.cgi.in b/support/phf_abuse_log.cgi.in
new file mode 100644
index 0000000..39900bf
--- /dev/null
+++ b/support/phf_abuse_log.cgi.in
@@ -0,0 +1,38 @@
+#!@perlbin@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# This script is used to detect people trying to abuse the security hole which
+# existed in A CGI script direstributed with Apache 1.0.3 and earlier versions.
+# You can redirect them to here using the "<Location /cgi-bin/phf*>" suggestion
+# in httpd.conf.
+#
+# The format logged to is
+# "[date] remote_addr remote_host [date] referrer user_agent".
+
+$LOG = "/var/log/phf_log";
+
+require "ctime.pl";
+$when = &ctime(time);
+$when =~ s/\n//go;
+$ENV{HTTP_USER_AGENT} .= " via $ENV{HTTP_VIA}" if($ENV{HTTP_VIA});
+
+open(LOG, ">>$LOG") || die "boo hoo, phf_log $!";
+print LOG "[$when] $ENV{REMOTE_ADDR} $ENV{REMOTE_HOST} $ENV{$HTTP_REFERER} $ENV{HTTP_USER_AGENT}\n";
+close(LOG);
+
+print "Content-type: text/html\r\n\r\n<BLINK>Smile, you're on Candid Camera.</BLINK>\n";
diff --git a/support/rotatelogs.c b/support/rotatelogs.c
new file mode 100644
index 0000000..e0819da
--- /dev/null
+++ b/support/rotatelogs.c
@@ -0,0 +1,810 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_errno.h"
+#include "apr_file_io.h"
+#include "apr_file_info.h"
+#include "apr_general.h"
+#include "apr_time.h"
+#include "apr_getopt.h"
+#include "apr_thread_proc.h"
+#include "apr_signal.h"
+#if APR_FILES_AS_SOCKETS
+#include "apr_poll.h"
+#endif
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#define BUFSIZE 65536
+
+#define ROTATE_NONE 0
+#define ROTATE_NEW 1
+#define ROTATE_TIME 2
+#define ROTATE_SIZE 3
+#define ROTATE_FORCE 4
+
+static const char *const ROTATE_REASONS[] = {
+ "None",
+ "Open a new file",
+ "Time interval expired",
+ "Maximum size reached",
+ "Forced rotation",
+ NULL
+};
+
+typedef struct rotate_config rotate_config_t;
+
+struct rotate_config {
+ unsigned int sRotation;
+ int tRotation;
+ int utc_offset;
+ int use_localtime;
+ int use_strftime;
+ int force_open;
+ int verbose;
+ int echo;
+ char *szLogRoot;
+ int truncate;
+ int truncate_rotated_only;
+ const char *linkfile;
+ const char *postrotate_prog;
+#if APR_FILES_AS_SOCKETS
+ int create_empty;
+#endif
+ int num_files;
+ int create_path;
+};
+
+typedef struct rotate_status rotate_status_t;
+
+/* "adjusted_time_t" is used to store Unix time (seconds since epoch)
+ * which has been adjusted for some timezone fudge factor. It should
+ * be used for storing the return values from get_now(). A typedef is
+ * used since this type is similar to time_t, but different. */
+typedef long adjusted_time_t;
+
+/* Structure to contain relevant logfile state: fd, pool and
+ * filename. */
+struct logfile {
+ apr_pool_t *pool;
+ apr_file_t *fd;
+ char name[APR_PATH_MAX];
+};
+
+struct rotate_status {
+ struct logfile current; /* current logfile. */
+ apr_pool_t *pool; /* top-level pool */
+ int rotateReason;
+ adjusted_time_t tLogEnd;
+ int nMessCount;
+ int fileNum;
+};
+
+static rotate_config_t config;
+static rotate_status_t status;
+
+static void usage(const char *argv0, const char *reason)
+{
+ if (reason) {
+ fprintf(stderr, "%s\n", reason);
+ }
+ fprintf(stderr,
+#if APR_FILES_AS_SOCKETS
+ "Usage: %s [-vlfDtTec] [-L linkname] [-p prog] [-n number] <logfile> "
+#else
+ "Usage: %s [-vlfDtTe] [-L linkname] [-p prog] [-n number] <logfile> "
+#endif
+ "{<rotation time in seconds>|<rotation size>(B|K|M|G)} "
+ "[offset minutes from UTC]\n\n",
+ argv0);
+#ifdef OS2
+ fprintf(stderr,
+ "Add this:\n\nTransferLog \"|%s.exe /some/where 86400\"\n\n",
+ argv0);
+#else
+ fprintf(stderr,
+ "Add this:\n\nTransferLog \"|%s /some/where 86400\"\n\n",
+ argv0);
+ fprintf(stderr,
+ "or \n\nTransferLog \"|%s /some/where 5M\"\n\n", argv0);
+#endif
+ fprintf(stderr,
+ "to httpd.conf. By default, the generated name will be\n"
+ "<logfile>.nnnn where nnnn is the system time at which the log\n"
+ "nominally starts (N.B. if using a rotation time, the time will\n"
+ "always be a multiple of the rotation time, so you can synchronize\n"
+ "cron scripts with it). If <logfile> contains strftime conversion\n"
+ "specifications, those will be used instead. At the end of each\n"
+ "rotation time or when the file size is reached a new log is\n"
+ "started.\n"
+ "\n"
+ "Options:\n"
+ " -v Verbose operation. Messages are written to stderr.\n"
+ " -l Base rotation on local time instead of UTC.\n"
+ " -L path Create hard link from current log to specified path.\n"
+ " -p prog Run specified program after opening a new log file. See below.\n"
+ " -f Force opening of log on program start.\n"
+ " -D Create parent directories of log file.\n"
+ " -t Truncate logfile instead of rotating, tail friendly.\n"
+ " -T Truncate logfiles opened for rotation, but not the initial logfile.\n"
+ " -e Echo log to stdout for further processing.\n"
+#if APR_FILES_AS_SOCKETS
+ " -c Create log even if it is empty.\n"
+#endif
+ " -n num Rotate file by adding suffixes '.1', '.2', ..., '.num'.\n"
+ "\n"
+ "The program for '-p' is invoked as \"[prog] <curfile> [<prevfile>]\"\n"
+ "where <curfile> is the filename of the newly opened logfile, and\n"
+ "<prevfile>, if given, is the filename of the previously used logfile.\n"
+ "\n");
+ exit(1);
+}
+
+/* This function returns the current Unix time (time_t) adjusted for
+ * any configured or derived local time offset. The offset applied is
+ * returned via *offset. */
+static adjusted_time_t get_now(rotate_config_t *config, apr_int32_t *offset)
+{
+ apr_time_t tNow = apr_time_now();
+ apr_int32_t utc_offset;
+
+ if (config->use_localtime) {
+ /* Check for our UTC offset before using it, since it might
+ * change if there's a switch between standard and daylight
+ * savings time.
+ */
+ apr_time_exp_t lt;
+ apr_time_exp_lt(&lt, tNow);
+ utc_offset = lt.tm_gmtoff;
+ }
+ else {
+ utc_offset = config->utc_offset;
+ }
+
+ if (offset)
+ *offset = utc_offset;
+
+ return apr_time_sec(tNow) + utc_offset;
+}
+
+/*
+ * Close a file and destroy the associated pool.
+ */
+static void close_logfile(rotate_config_t *config, struct logfile *logfile)
+{
+ if (config->verbose) {
+ fprintf(stderr, "Closing file %s\n", logfile->name);
+ }
+ apr_file_close(logfile->fd);
+ apr_pool_destroy(logfile->pool);
+}
+
+/*
+ * Dump the configuration parsing result to STDERR.
+ */
+static void dumpConfig (rotate_config_t *config)
+{
+ fprintf(stderr, "Rotation time interval: %12d\n", config->tRotation);
+ fprintf(stderr, "Rotation size interval: %12d\n", config->sRotation);
+ fprintf(stderr, "Rotation time UTC offset: %12d\n", config->utc_offset);
+ fprintf(stderr, "Rotation based on localtime: %12s\n", config->use_localtime ? "yes" : "no");
+ fprintf(stderr, "Rotation file date pattern: %12s\n", config->use_strftime ? "yes" : "no");
+ fprintf(stderr, "Rotation file forced open: %12s\n", config->force_open ? "yes" : "no");
+ fprintf(stderr, "Create parent directories: %12s\n", config->create_path ? "yes" : "no");
+ fprintf(stderr, "Rotation verbose: %12s\n", config->verbose ? "yes" : "no");
+#if APR_FILES_AS_SOCKETS
+ fprintf(stderr, "Rotation create empty logs: %12s\n", config->create_empty ? "yes" : "no");
+#endif
+ fprintf(stderr, "Rotation file name: %21s\n", config->szLogRoot);
+ fprintf(stderr, "Post-rotation prog: %21s\n", config->postrotate_prog ? config->postrotate_prog : "not used");
+}
+
+/*
+ * Check whether we need to rotate.
+ * Possible reasons are:
+ * - No log file open (ROTATE_NEW)
+ * - User forces us to rotate (ROTATE_FORCE)
+ * - Our log file size is already bigger than the
+ * allowed maximum (ROTATE_SIZE)
+ * - The next log time interval expired (ROTATE_TIME)
+ *
+ * When size and time constraints are both given,
+ * it suffices that one of them is fulfilled.
+ */
+static void checkRotate(rotate_config_t *config, rotate_status_t *status)
+{
+ if (status->current.fd == NULL) {
+ status->rotateReason = ROTATE_NEW;
+ }
+ else if (config->sRotation) {
+ apr_finfo_t finfo;
+ apr_off_t current_size = -1;
+
+ if (apr_file_info_get(&finfo, APR_FINFO_SIZE, status->current.fd) == APR_SUCCESS) {
+ current_size = finfo.size;
+ }
+
+ if (current_size > config->sRotation) {
+ status->rotateReason = ROTATE_SIZE;
+ }
+ else if (config->tRotation) {
+ if (get_now(config, NULL) >= status->tLogEnd) {
+ status->rotateReason = ROTATE_TIME;
+ }
+ }
+ }
+ else if (config->tRotation) {
+ if (get_now(config, NULL) >= status->tLogEnd) {
+ status->rotateReason = ROTATE_TIME;
+ }
+ }
+ else {
+ fprintf(stderr, "No rotation time or size specified\n");
+ exit(2);
+ }
+
+ if (status->rotateReason != ROTATE_NONE && config->verbose) {
+ fprintf(stderr, "File rotation needed, reason: %s\n", ROTATE_REASONS[status->rotateReason]);
+ }
+}
+
+/*
+ * Handle post-rotate processing.
+ */
+static void post_rotate(apr_pool_t *pool, struct logfile *newlog,
+ rotate_config_t *config, rotate_status_t *status)
+{
+ apr_status_t rv;
+ char error[120];
+ apr_procattr_t *pattr;
+ const char *argv[4];
+ apr_proc_t proc;
+
+ /* Handle link file, if configured. */
+ if (config->linkfile) {
+ apr_file_remove(config->linkfile, newlog->pool);
+ if (config->verbose) {
+ fprintf(stderr, "Linking %s to %s\n", newlog->name, config->linkfile);
+ }
+ rv = apr_file_link(newlog->name, config->linkfile);
+ if (rv != APR_SUCCESS) {
+ apr_strerror(rv, error, sizeof error);
+ fprintf(stderr, "Error linking file %s to %s (%s)\n",
+ newlog->name, config->linkfile, error);
+ exit(2);
+ }
+ }
+
+ if (!config->postrotate_prog) {
+ /* Nothing more to do. */
+ return;
+ }
+
+ /* Collect any zombies from a previous run, but don't wait. */
+ while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT, pool) == APR_CHILD_DONE)
+ /* noop */;
+
+ if ((rv = apr_procattr_create(&pattr, pool)) != APR_SUCCESS) {
+ fprintf(stderr,
+ "post_rotate: apr_procattr_create failed for '%s': %s\n",
+ config->postrotate_prog,
+ apr_strerror(rv, error, sizeof(error)));
+ return;
+ }
+
+ rv = apr_procattr_error_check_set(pattr, 1);
+ if (rv == APR_SUCCESS)
+ rv = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV);
+
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr,
+ "post_rotate: could not set up process attributes for '%s': %s\n",
+ config->postrotate_prog,
+ apr_strerror(rv, error, sizeof(error)));
+ return;
+ }
+
+ argv[0] = config->postrotate_prog;
+ argv[1] = newlog->name;
+ if (status->current.fd) {
+ argv[2] = status->current.name;
+ argv[3] = NULL;
+ }
+ else {
+ argv[2] = NULL;
+ }
+
+ if (config->verbose)
+ fprintf(stderr, "Calling post-rotate program: %s\n", argv[0]);
+
+ rv = apr_proc_create(&proc, argv[0], argv, NULL, pattr, pool);
+ if (rv != APR_SUCCESS) {
+ fprintf(stderr, "Could not spawn post-rotate process '%s': %s\n",
+ config->postrotate_prog,
+ apr_strerror(rv, error, sizeof(error)));
+ return;
+ }
+}
+
+/* After a error, truncate the current file and write out an error
+ * message, which must be contained in message. The process is
+ * terminated on failure. */
+static void truncate_and_write_error(rotate_status_t *status, const char *message)
+{
+ apr_size_t buflen = strlen(message);
+
+ if (apr_file_trunc(status->current.fd, 0) != APR_SUCCESS) {
+ fprintf(stderr, "Error truncating the file %s\n", status->current.name);
+ exit(2);
+ }
+ if (apr_file_write_full(status->current.fd, message, buflen, NULL) != APR_SUCCESS) {
+ fprintf(stderr, "Error writing error (%s) to the file %s\n",
+ message, status->current.name);
+ exit(2);
+ }
+}
+
+/*
+ * Open a new log file, and if successful
+ * also close the old one.
+ *
+ * The timestamp for the calculation of the file
+ * name of the new log file will be the actual millisecond
+ * timestamp, except when a regular rotation based on a time
+ * interval is configured and the previous interval
+ * is over. Then the timestamp is the starting time
+ * of the actual interval.
+ */
+static void doRotate(rotate_config_t *config, rotate_status_t *status)
+{
+ apr_int32_t offset;
+ adjusted_time_t now, tLogStart;
+ apr_status_t rv;
+ struct logfile newlog;
+ int thisLogNum = -1;
+ int oldreason = status->rotateReason;
+ int truncate = config->truncate;
+
+ /* Retrieve local-time-adjusted-Unix-time. */
+ now = get_now(config, &offset);
+
+ status->rotateReason = ROTATE_NONE;
+
+ if (config->tRotation) {
+ adjusted_time_t tLogEnd;
+
+ tLogStart = (now / config->tRotation) * config->tRotation;
+ tLogEnd = tLogStart + config->tRotation;
+ /*
+ * Check if rotation was forced and the last rotation
+ * interval is not yet over. Use the value of now instead
+ * of the time interval boundary for the file name then.
+ */
+ if (tLogStart < status->tLogEnd) {
+ tLogStart = now;
+ }
+ status->tLogEnd = tLogEnd;
+ }
+ else {
+ tLogStart = now;
+ }
+
+ if (config->use_strftime) {
+ apr_time_t tNow = apr_time_from_sec(tLogStart);
+ apr_time_exp_t e;
+ apr_size_t rs;
+
+ /* Explode the local-time-adjusted-Unix-time into a struct tm,
+ * first *reversing* local-time-adjustment applied by
+ * get_now() if we are using localtime. */
+ if (config->use_localtime)
+ apr_time_exp_lt(&e, tNow - apr_time_from_sec(offset));
+ else
+ apr_time_exp_gmt(&e, tNow);
+ apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e);
+ }
+ else {
+ if (config->truncate) {
+ apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot);
+ }
+ else if (config->num_files > 0) {
+ if (status->fileNum == -1 || status->fileNum == (config->num_files - 1)) {
+ thisLogNum = 0;
+ apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot);
+ }
+ else {
+ thisLogNum = status->fileNum + 1;
+ apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%d", config->szLogRoot, thisLogNum);
+ }
+ }
+ else {
+ apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%010ld", config->szLogRoot,
+ tLogStart);
+ }
+ }
+ apr_pool_create(&newlog.pool, status->pool);
+ if (config->create_path) {
+ char *ptr = strrchr(newlog.name, '/');
+ if (ptr && ptr > newlog.name) {
+ char *path = apr_pstrmemdup(newlog.pool, newlog.name, ptr - newlog.name);
+ if (config->verbose) {
+ fprintf(stderr, "Creating directory tree %s\n", path);
+ }
+ rv = apr_dir_make_recursive(path, APR_FPROT_OS_DEFAULT, newlog.pool);
+ if (rv != APR_SUCCESS) {
+ char error[120];
+
+ apr_strerror(rv, error, sizeof error);
+ fprintf(stderr, "Could not create directory '%s' (%s)\n", path, error);
+ exit(2);
+ }
+ }
+ }
+ if (config->verbose) {
+ fprintf(stderr, "Opening file %s\n", newlog.name);
+ }
+
+ if (!truncate) {
+ /* -n and -T truncate subsequent files only. */
+ if (status->current.fd &&
+ (config->num_files > 0 || config->truncate_rotated_only)) {
+ truncate = 1;
+ }
+ }
+ rv = apr_file_open(&newlog.fd, newlog.name,
+ APR_WRITE | APR_CREATE | APR_APPEND
+ | (truncate ? APR_TRUNCATE : 0),
+ APR_OS_DEFAULT, newlog.pool);
+ if (rv == APR_SUCCESS) {
+ /* Handle post-rotate processing. */
+ post_rotate(newlog.pool, &newlog, config, status);
+
+ status->fileNum = thisLogNum;
+ /* Close out old (previously 'current') logfile, if any. */
+ if (status->current.fd) {
+ close_logfile(config, &status->current);
+ }
+
+ /* New log file is now 'current'. */
+ status->current = newlog;
+
+ /* The first write to the initial file hasn't checked for size.
+ * In the normalized timestamp case and the custom strftime case with
+ * any reasonable accuracy, it's futile as the rotation will pick the
+ * same filename again.
+ * For -n, when not truncating, check and rotate.
+ */
+ if (config->num_files > 0 && oldreason == ROTATE_NEW && !config->truncate) {
+ checkRotate(config, status);
+ if (status->rotateReason != ROTATE_NONE) {
+ doRotate(config, status);
+ }
+ }
+ }
+ else {
+ char *error = apr_psprintf(newlog.pool, "%pm", &rv);
+ char *message;
+
+ /* Uh-oh. Failed to open the new log file. Try to clear
+ * the previous log file, note the lost log entries,
+ * and keep on truckin'. */
+ if (status->current.fd == NULL) {
+ fprintf(stderr, "Could not open log file '%s' (%s)\n", newlog.name, error);
+ exit(2);
+ }
+
+ /* Try to keep this error message constant length
+ * in case it occurs several times. */
+ message = apr_psprintf(newlog.pool,
+ "Resetting log file due to error opening "
+ "new log file, %10d messages lost: %-25.25s\n",
+ status->nMessCount, error);
+
+ truncate_and_write_error(status, message);
+
+ /* Throw away new state; it isn't going to be used. */
+ apr_pool_destroy(newlog.pool);
+ }
+
+ status->nMessCount = 0;
+}
+
+/*
+ * Get a size or time param from a string.
+ * Parameter 'last' indicates, whether the
+ * argument is the last commandline argument.
+ * UTC offset is only allowed as a last argument
+ * in order to make is distinguishable from the
+ * rotation interval time.
+ */
+static const char *get_time_or_size(rotate_config_t *config,
+ const char *arg, int last) {
+ char *ptr = NULL;
+ /* Byte multiplier */
+ unsigned int mult = 1;
+ if ((ptr = strchr(arg, 'B')) != NULL) { /* Found KB size */
+ mult = 1;
+ }
+ else if ((ptr = strchr(arg, 'K')) != NULL) { /* Found KB size */
+ mult = 1024;
+ }
+ else if ((ptr = strchr(arg, 'M')) != NULL) { /* Found MB size */
+ mult = 1024 * 1024;
+ }
+ else if ((ptr = strchr(arg, 'G')) != NULL) { /* Found GB size */
+ mult = 1024 * 1024 * 1024;
+ }
+ if (ptr) { /* rotation based on file size */
+ if (config->sRotation > 0) {
+ return "Rotation size parameter allowed only once";
+ }
+ if (*(ptr+1) == '\0') {
+ config->sRotation = atoi(arg) * mult;
+ }
+ if (config->sRotation == 0) {
+ return "Invalid rotation size parameter";
+ }
+ }
+ else if ((config->sRotation > 0 || config->tRotation > 0) && last) {
+ /* rotation based on elapsed time */
+ if (config->use_localtime) {
+ return "UTC offset parameter is not valid with -l";
+ }
+ config->utc_offset = atoi(arg) * 60;
+ }
+ else { /* rotation based on elapsed time */
+ if (config->tRotation > 0) {
+ return "Rotation time parameter allowed only once";
+ }
+ config->tRotation = atoi(arg);
+ if (config->tRotation <= 0) {
+ return "Invalid rotation time parameter";
+ }
+ }
+ return NULL;
+}
+
+int main (int argc, const char * const argv[])
+{
+ char buf[BUFSIZE];
+ apr_size_t nRead, nWrite;
+ apr_file_t *f_stdin;
+ apr_file_t *f_stdout;
+ apr_getopt_t *opt;
+ apr_status_t rv;
+ char c;
+ const char *opt_arg;
+ const char *err = NULL;
+#if APR_FILES_AS_SOCKETS
+ apr_pollfd_t pollfd = { 0 };
+ apr_status_t pollret = APR_SUCCESS;
+ long polltimeout;
+#endif
+
+ apr_app_initialize(&argc, &argv, NULL);
+ atexit(apr_terminate);
+
+ memset(&config, 0, sizeof config);
+ memset(&status, 0, sizeof status);
+ status.rotateReason = ROTATE_NONE;
+
+ apr_pool_create(&status.pool, NULL);
+ apr_getopt_init(&opt, status.pool, argc, argv);
+#if APR_FILES_AS_SOCKETS
+ while ((rv = apr_getopt(opt, "lL:p:fDtTvecn:", &c, &opt_arg)) == APR_SUCCESS) {
+#else
+ while ((rv = apr_getopt(opt, "lL:p:fDtTven:", &c, &opt_arg)) == APR_SUCCESS) {
+#endif
+ switch (c) {
+ case 'l':
+ config.use_localtime = 1;
+ break;
+ case 'L':
+ config.linkfile = opt_arg;
+ break;
+ case 'p':
+ config.postrotate_prog = opt_arg;
+#ifdef SIGCHLD
+ /* Prevent creation of zombies (on modern Unix systems). */
+ apr_signal(SIGCHLD, SIG_IGN);
+#endif
+ break;
+ case 'f':
+ config.force_open = 1;
+ break;
+ case 'D':
+ config.create_path = 1;
+ break;
+ case 't':
+ config.truncate = 1;
+ break;
+ case 'T':
+ config.truncate_rotated_only = 1;
+ break;
+ case 'v':
+ config.verbose = 1;
+ break;
+ case 'e':
+ config.echo = 1;
+ break;
+#if APR_FILES_AS_SOCKETS
+ case 'c':
+ config.create_empty = 1;
+ break;
+#endif
+ case 'n':
+ config.num_files = atoi(opt_arg);
+ status.fileNum = -1;
+ break;
+ }
+ }
+
+ if (rv != APR_EOF) {
+ usage(argv[0], NULL /* specific error message already issued */ );
+ }
+
+ /*
+ * After the initial flags we need 2 to 4 arguments,
+ * the file name, either the rotation interval time or size
+ * or both of them, and optionally the UTC offset.
+ */
+ if ((argc - opt->ind < 2) || (argc - opt->ind > 4) ) {
+ usage(argv[0], "Incorrect number of arguments");
+ }
+
+ rv = apr_filepath_merge(&config.szLogRoot, "", argv[opt->ind++],
+ APR_FILEPATH_TRUENAME, status.pool);
+ if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
+ usage(argv[0], "Invalid filename given");
+ }
+
+ /* Read in the remaining flags, namely time, size and UTC offset. */
+ for(; opt->ind < argc; opt->ind++) {
+ if ((err = get_time_or_size(&config, argv[opt->ind],
+ opt->ind < argc - 1 ? 0 : 1)) != NULL) {
+ usage(argv[0], err);
+ }
+ }
+
+ config.use_strftime = (strchr(config.szLogRoot, '%') != NULL);
+
+ if (config.use_strftime && config.num_files > 0) {
+ fprintf(stderr, "Cannot use -n with %% in filename\n");
+ exit(1);
+ }
+
+ if (status.fileNum == -1 && config.num_files < 1) {
+ fprintf(stderr, "Invalid -n argument\n");
+ exit(1);
+ }
+
+ if (apr_file_open_stdin(&f_stdin, status.pool) != APR_SUCCESS) {
+ fprintf(stderr, "Unable to open stdin\n");
+ exit(1);
+ }
+
+ if (apr_file_open_stdout(&f_stdout, status.pool) != APR_SUCCESS) {
+ fprintf(stderr, "Unable to open stdout\n");
+ exit(1);
+ }
+
+ /*
+ * Write out result of config parsing if verbose is set.
+ */
+ if (config.verbose) {
+ dumpConfig(&config);
+ }
+
+#if APR_FILES_AS_SOCKETS
+ if (config.create_empty && config.tRotation) {
+ pollfd.p = status.pool;
+ pollfd.desc_type = APR_POLL_FILE;
+ pollfd.reqevents = APR_POLLIN;
+ pollfd.desc.f = f_stdin;
+ }
+#endif
+
+ /*
+ * Immediately open the logfile as we start, if we were forced
+ * to do so via '-f'.
+ */
+ if (config.force_open) {
+ doRotate(&config, &status);
+ }
+
+ for (;;) {
+ nRead = sizeof(buf);
+#if APR_FILES_AS_SOCKETS
+ if (config.create_empty && config.tRotation) {
+ polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation;
+ if (polltimeout <= 0) {
+ pollret = APR_TIMEUP;
+ }
+ else {
+ pollret = apr_poll(&pollfd, 1, &pollret, apr_time_from_sec(polltimeout));
+ }
+ }
+ if (pollret == APR_SUCCESS) {
+ rv = apr_file_read(f_stdin, buf, &nRead);
+ if (APR_STATUS_IS_EOF(rv)) {
+ break;
+ }
+ else if (rv != APR_SUCCESS) {
+ exit(3);
+ }
+ }
+ else if (pollret == APR_TIMEUP) {
+ *buf = 0;
+ nRead = 0;
+ }
+ else {
+ fprintf(stderr, "Unable to poll stdin\n");
+ exit(5);
+ }
+#else /* APR_FILES_AS_SOCKETS */
+ rv = apr_file_read(f_stdin, buf, &nRead);
+ if (APR_STATUS_IS_EOF(rv)) {
+ break;
+ }
+ else if (rv != APR_SUCCESS) {
+ exit(3);
+ }
+#endif /* APR_FILES_AS_SOCKETS */
+ checkRotate(&config, &status);
+ if (status.rotateReason != ROTATE_NONE) {
+ doRotate(&config, &status);
+ }
+
+ nWrite = nRead;
+ rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite);
+ if (nWrite != nRead) {
+ apr_off_t cur_offset;
+ apr_pool_t *pool;
+ char *error;
+
+ cur_offset = 0;
+ if (apr_file_seek(status.current.fd, APR_CUR, &cur_offset) != APR_SUCCESS) {
+ cur_offset = -1;
+ }
+ status.nMessCount++;
+ apr_pool_create(&pool, status.pool);
+ error = apr_psprintf(pool, "Error %d writing to log file at offset %"
+ APR_OFF_T_FMT ". %10d messages lost (%pm)\n",
+ rv, cur_offset, status.nMessCount, &rv);
+
+ truncate_and_write_error(&status, error);
+ apr_pool_destroy(pool);
+ }
+ else {
+ status.nMessCount++;
+ }
+ if (config.echo) {
+ if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) {
+ fprintf(stderr, "Unable to write to stdout\n");
+ exit(4);
+ }
+ }
+ }
+
+ return 0; /* reached only at stdin EOF. */
+}
diff --git a/support/rotatelogs.dep b/support/rotatelogs.dep
new file mode 100644
index 0000000..5b27972
--- /dev/null
+++ b/support/rotatelogs.dep
@@ -0,0 +1,28 @@
+# Microsoft Developer Studio Generated Dependency File, included by rotatelogs.mak
+
+..\build\win32\httpd.rc : \
+ "..\include\ap_release.h"\
+
+
+.\rotatelogs.c : \
+ "..\srclib\apr\include\apr.h"\
+ "..\srclib\apr\include\apr_allocator.h"\
+ "..\srclib\apr\include\apr_errno.h"\
+ "..\srclib\apr\include\apr_file_info.h"\
+ "..\srclib\apr\include\apr_file_io.h"\
+ "..\srclib\apr\include\apr_general.h"\
+ "..\srclib\apr\include\apr_getopt.h"\
+ "..\srclib\apr\include\apr_inherit.h"\
+ "..\srclib\apr\include\apr_lib.h"\
+ "..\srclib\apr\include\apr_network_io.h"\
+ "..\srclib\apr\include\apr_poll.h"\
+ "..\srclib\apr\include\apr_pools.h"\
+ "..\srclib\apr\include\apr_signal.h"\
+ "..\srclib\apr\include\apr_strings.h"\
+ "..\srclib\apr\include\apr_tables.h"\
+ "..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\srclib\apr\include\apr_thread_proc.h"\
+ "..\srclib\apr\include\apr_time.h"\
+ "..\srclib\apr\include\apr_user.h"\
+ "..\srclib\apr\include\apr_want.h"\
+
diff --git a/support/rotatelogs.dsp b/support/rotatelogs.dsp
new file mode 100644
index 0000000..abfa9c1
--- /dev/null
+++ b/support/rotatelogs.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="rotatelogs" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=rotatelogs - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "rotatelogs.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "rotatelogs.mak" CFG="rotatelogs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "rotatelogs - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "rotatelogs - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "rotatelogs - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/rotatelogs_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\rotatelogs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/rotatelogs_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\rotatelogs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "rotatelogs - Win32 Release"
+# Name "rotatelogs - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\rotatelogs.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/rotatelogs.mak b/support/rotatelogs.mak
new file mode 100644
index 0000000..f7a6fd4
--- /dev/null
+++ b/support/rotatelogs.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on rotatelogs.dsp
+!IF "$(CFG)" == ""
+CFG=rotatelogs - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to rotatelogs - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "rotatelogs - Win32 Release" && "$(CFG)" != "rotatelogs - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "rotatelogs.mak" CFG="rotatelogs - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "rotatelogs - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "rotatelogs - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "rotatelogs - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\rotatelogs.obj"
+ -@erase "$(INTDIR)\rotatelogs.res"
+ -@erase "$(INTDIR)\rotatelogs_src.idb"
+ -@erase "$(INTDIR)\rotatelogs_src.pdb"
+ -@erase "$(OUTDIR)\rotatelogs.exe"
+ -@erase "$(OUTDIR)\rotatelogs.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\rotatelogs_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\rotatelogs.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\rotatelogs.pdb" /debug /out:"$(OUTDIR)\rotatelogs.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\rotatelogs.obj" \
+ "$(INTDIR)\rotatelogs.res" \
+ "..\srclib\apr\LibR\apr-1.lib" \
+ "..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\rotatelogs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\rotatelogs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\rotatelogs.exe"
+ if exist .\Release\rotatelogs.exe.manifest mt.exe -manifest .\Release\rotatelogs.exe.manifest -outputresource:.\Release\rotatelogs.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\rotatelogs.obj"
+ -@erase "$(INTDIR)\rotatelogs.res"
+ -@erase "$(INTDIR)\rotatelogs_src.idb"
+ -@erase "$(INTDIR)\rotatelogs_src.pdb"
+ -@erase "$(OUTDIR)\rotatelogs.exe"
+ -@erase "$(OUTDIR)\rotatelogs.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\rotatelogs_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\rotatelogs.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\rotatelogs.pdb" /debug /out:"$(OUTDIR)\rotatelogs.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\rotatelogs.obj" \
+ "$(INTDIR)\rotatelogs.res" \
+ "..\srclib\apr\LibD\apr-1.lib" \
+ "..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\rotatelogs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\rotatelogs.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\rotatelogs.exe"
+ if exist .\Debug\rotatelogs.exe.manifest mt.exe -manifest .\Debug\rotatelogs.exe.manifest -outputresource:.\Debug\rotatelogs.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("rotatelogs.dep")
+!INCLUDE "rotatelogs.dep"
+!ELSE
+!MESSAGE Warning: cannot find "rotatelogs.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "rotatelogs - Win32 Release" || "$(CFG)" == "rotatelogs - Win32 Debug"
+
+!IF "$(CFG)" == "rotatelogs - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+!IF "$(CFG)" == "rotatelogs - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support"
+
+!ENDIF
+
+SOURCE=..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "rotatelogs - Win32 Release"
+
+
+"$(INTDIR)\rotatelogs.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug"
+
+
+"$(INTDIR)\rotatelogs.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\rotatelogs.c
+
+"$(INTDIR)\rotatelogs.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/support/split-logfile.in b/support/split-logfile.in
new file mode 100644
index 0000000..e5abfc7
--- /dev/null
+++ b/support/split-logfile.in
@@ -0,0 +1,69 @@
+#!@perlbin@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# This script will take a combined Web server access
+# log file and break its contents into separate files.
+# It assumes that the first field of each line is the
+# virtual host identity (put there by "%v"), and that
+# the logfiles should be named that+".log" in the current
+# directory.
+#
+# The combined log file is read from stdin. Records read
+# will be appended to any existing log files.
+#
+use strict;
+use warnings;
+
+my %log_file = ();
+
+while (my $log_line = <STDIN>) {
+ #
+ # Get the first token from the log record; it's the
+ # identity of the virtual host to which the record
+ # applies.
+ #
+ my ($vhost) = split (/\s/, $log_line);
+ #
+ # Normalize the virtual host name to all lowercase.
+ # If it's blank, the request was handled by the default
+ # server, so supply a default name. This shouldn't
+ # happen, but caution rocks.
+ #
+ $vhost = lc ($vhost) || "access";
+ #
+ # if the vhost contains a "/" or "\", it is illegal so just use
+ # the default log to avoid any security issues due if it is interprted
+ # as a directory separator.
+ if ($vhost =~ m#[/\\]#) { $vhost = "access" }
+ #
+ # If the log file for this virtual host isn't opened
+ # yet, do it now.
+ #
+ if (! $log_file{$vhost}) {
+ open $log_file{$vhost}, ">>${vhost}.log"
+ or die ("Can't open ${vhost}.log");
+ }
+ #
+ # Strip off the first token (which may be null in the
+ # case of the default server), and write the edited
+ # record to the current log file.
+ #
+ $log_line =~ s/^\S*\s+//;
+ print {$log_file{$vhost}} $log_line;
+}
+exit 0;
diff --git a/support/suexec.c b/support/suexec.c
new file mode 100644
index 0000000..c2eb0b6
--- /dev/null
+++ b/support/suexec.c
@@ -0,0 +1,685 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache
+ *
+ ***********************************************************************
+ *
+ * NOTE! : DO NOT edit this code!!! Unless you know what you are doing,
+ * editing this code might open up your system in unexpected
+ * ways to would-be crackers. Every precaution has been taken
+ * to make this code as safe as possible; alter it at your own
+ * risk.
+ *
+ ***********************************************************************
+ *
+ *
+ */
+
+#include "apr.h"
+#include "ap_config.h"
+#include "suexec.h"
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <time.h>
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#if APR_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifdef AP_LOG_SYSLOG
+#include <syslog.h>
+#endif
+
+#if defined(PATH_MAX)
+#define AP_MAXPATH PATH_MAX
+#elif defined(MAXPATHLEN)
+#define AP_MAXPATH MAXPATHLEN
+#else
+#define AP_MAXPATH 8192
+#endif
+
+#define AP_ENVBUF 256
+
+extern char **environ;
+
+#ifdef AP_LOG_SYSLOG
+/* Syslog support. */
+#if !defined(AP_LOG_FACILITY) && defined(LOG_AUTHPRIV)
+#define AP_LOG_FACILITY LOG_AUTHPRIV
+#elif !defined(AP_LOG_FACILITY)
+#define AP_LOG_FACILITY LOG_AUTH
+#endif
+
+static int log_open;
+#else
+/* Non-syslog support. */
+static FILE *log = NULL;
+#endif
+
+static const char *const safe_env_lst[] =
+{
+ /* variable name starts with */
+ "HTTP_",
+ "SSL_",
+
+ /* variable name is */
+ "AUTH_TYPE=",
+ "CONTENT_LENGTH=",
+ "CONTENT_TYPE=",
+ "CONTEXT_DOCUMENT_ROOT=",
+ "CONTEXT_PREFIX=",
+ "DATE_GMT=",
+ "DATE_LOCAL=",
+ "DOCUMENT_ARGS=",
+ "DOCUMENT_NAME=",
+ "DOCUMENT_PATH_INFO=",
+ "DOCUMENT_ROOT=",
+ "DOCUMENT_URI=",
+ "GATEWAY_INTERFACE=",
+ "HTTPS=",
+ "LAST_MODIFIED=",
+ "PATH_INFO=",
+ "PATH_TRANSLATED=",
+ "QUERY_STRING=",
+ "QUERY_STRING_UNESCAPED=",
+ "REMOTE_ADDR=",
+ "REMOTE_HOST=",
+ "REMOTE_IDENT=",
+ "REMOTE_PORT=",
+ "REMOTE_USER=",
+ "REDIRECT_ERROR_NOTES=",
+ "REDIRECT_HANDLER=",
+ "REDIRECT_QUERY_STRING=",
+ "REDIRECT_REMOTE_USER=",
+ "REDIRECT_SCRIPT_FILENAME=",
+ "REDIRECT_STATUS=",
+ "REDIRECT_URL=",
+ "REQUEST_METHOD=",
+ "REQUEST_SCHEME=",
+ "REQUEST_URI=",
+ "SCRIPT_FILENAME=",
+ "SCRIPT_NAME=",
+ "SCRIPT_URI=",
+ "SCRIPT_URL=",
+ "SERVER_ADDR=",
+ "SERVER_ADMIN=",
+ "SERVER_NAME=",
+ "SERVER_PORT=",
+ "SERVER_PROTOCOL=",
+ "SERVER_SIGNATURE=",
+ "SERVER_SOFTWARE=",
+ "UNIQUE_ID=",
+ "USER_NAME=",
+ "TZ=",
+ NULL
+};
+
+static void log_err(const char *fmt,...)
+ __attribute__((format(printf,1,2)));
+static void log_no_err(const char *fmt,...)
+ __attribute__((format(printf,1,2)));
+static void err_output(int is_error, const char *fmt, va_list ap)
+ __attribute__((format(printf,2,0)));
+
+static void err_output(int is_error, const char *fmt, va_list ap)
+{
+#if defined(AP_LOG_SYSLOG)
+ if (!log_open) {
+ openlog("suexec", LOG_PID, AP_LOG_FACILITY);
+ log_open = 1;
+ }
+
+ vsyslog(is_error ? LOG_ERR : LOG_INFO, fmt, ap);
+#elif defined(AP_LOG_EXEC)
+ time_t timevar;
+ struct tm *lt;
+
+ if (!log) {
+#if defined(_LARGEFILE64_SOURCE) && HAVE_FOPEN64
+ if ((log = fopen64(AP_LOG_EXEC, "a")) == NULL) {
+#else
+ if ((log = fopen(AP_LOG_EXEC, "a")) == NULL) {
+#endif
+ fprintf(stderr, "suexec failure: could not open log file\n");
+ perror("fopen");
+ exit(1);
+ }
+ }
+
+ if (is_error) {
+ fprintf(stderr, "suexec policy violation: see suexec log for more "
+ "details\n");
+ }
+
+ time(&timevar);
+ lt = localtime(&timevar);
+
+ fprintf(log, "[%d-%.2d-%.2d %.2d:%.2d:%.2d]: ",
+ lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday,
+ lt->tm_hour, lt->tm_min, lt->tm_sec);
+
+ vfprintf(log, fmt, ap);
+
+ fflush(log);
+#endif /* AP_LOG_EXEC */
+ return;
+}
+
+static void log_err(const char *fmt,...)
+{
+#ifdef AP_LOG_EXEC
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_output(1, fmt, ap); /* 1 == is_error */
+ va_end(ap);
+#endif /* AP_LOG_EXEC */
+ return;
+}
+
+static void log_no_err(const char *fmt,...)
+{
+#ifdef AP_LOG_EXEC
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_output(0, fmt, ap); /* 0 == !is_error */
+ va_end(ap);
+#endif /* AP_LOG_EXEC */
+ return;
+}
+
+static void clean_env(void)
+{
+ char **cleanenv;
+ char **ep;
+ int cidx = 0;
+ int idx;
+
+ /* While cleaning the environment, the environment should be clean.
+ * (e.g. malloc() may get the name of a file for writing debugging info.
+ * Bad news if MALLOC_DEBUG_FILE is set to /etc/passwd. Sprintf() may be
+ * susceptible to bad locale settings....)
+ * (from PR 2790)
+ */
+ char **envp = environ;
+ char *empty_ptr = NULL;
+
+ environ = &empty_ptr; /* VERY safe environment */
+
+ if ((cleanenv = (char **) calloc(AP_ENVBUF, sizeof(char *))) == NULL) {
+ log_err("failed to malloc memory for environment\n");
+ exit(123);
+ }
+
+ cleanenv[cidx] = strdup("PATH=" AP_SAFE_PATH);
+ if (cleanenv[cidx] == NULL) {
+ log_err("failed to malloc memory for environment\n");
+ exit(124);
+ }
+ cidx++;
+
+ for (ep = envp; *ep && cidx < AP_ENVBUF-1; ep++) {
+ for (idx = 0; safe_env_lst[idx]; idx++) {
+ if (!strncmp(*ep, safe_env_lst[idx],
+ strlen(safe_env_lst[idx]))) {
+ cleanenv[cidx] = *ep;
+ cidx++;
+ break;
+ }
+ }
+ }
+
+ cleanenv[cidx] = NULL;
+
+ environ = cleanenv;
+}
+
+int main(int argc, char *argv[])
+{
+ int userdir = 0; /* ~userdir flag */
+ uid_t uid; /* user information */
+ gid_t gid; /* target group placeholder */
+ char *target_uname; /* target user name */
+ char *target_gname; /* target group name */
+ char *target_homedir; /* target home directory */
+ char *actual_uname; /* actual user name */
+ char *actual_gname; /* actual group name */
+ char *cmd; /* command to be executed */
+ char cwd[AP_MAXPATH]; /* current working directory */
+ char dwd[AP_MAXPATH]; /* docroot working directory */
+ struct passwd *pw; /* password entry holder */
+ struct group *gr; /* group entry holder */
+ struct stat dir_info; /* directory info holder */
+ struct stat prg_info; /* program info holder */
+
+ /*
+ * Start with a "clean" environment
+ */
+ clean_env();
+
+ /*
+ * Check existence/validity of the UID of the user
+ * running this program. Error out if invalid.
+ */
+ uid = getuid();
+ if ((pw = getpwuid(uid)) == NULL) {
+ log_err("crit: invalid uid: (%lu)\n", (unsigned long)uid);
+ exit(102);
+ }
+ /*
+ * See if this is a 'how were you compiled' request, and
+ * comply if so.
+ */
+ if ((argc > 1)
+ && (! strcmp(argv[1], "-V"))
+ && ((uid == 0)
+#ifdef _OSD_POSIX
+ /* User name comparisons are case insensitive on BS2000/OSD */
+ || (! strcasecmp(AP_HTTPD_USER, pw->pw_name)))
+#else /* _OSD_POSIX */
+ || (! strcmp(AP_HTTPD_USER, pw->pw_name)))
+#endif /* _OSD_POSIX */
+ ) {
+#ifdef AP_DOC_ROOT
+ fprintf(stderr, " -D AP_DOC_ROOT=\"%s\"\n", AP_DOC_ROOT);
+#endif
+#ifdef AP_GID_MIN
+ fprintf(stderr, " -D AP_GID_MIN=%d\n", AP_GID_MIN);
+#endif
+#ifdef AP_HTTPD_USER
+ fprintf(stderr, " -D AP_HTTPD_USER=\"%s\"\n", AP_HTTPD_USER);
+#endif
+#if defined(AP_LOG_SYSLOG)
+ fprintf(stderr, " -D AP_LOG_SYSLOG\n");
+#elif defined(AP_LOG_EXEC)
+ fprintf(stderr, " -D AP_LOG_EXEC=\"%s\"\n", AP_LOG_EXEC);
+#endif
+#ifdef AP_SAFE_PATH
+ fprintf(stderr, " -D AP_SAFE_PATH=\"%s\"\n", AP_SAFE_PATH);
+#endif
+#ifdef AP_SUEXEC_UMASK
+ fprintf(stderr, " -D AP_SUEXEC_UMASK=%03o\n", AP_SUEXEC_UMASK);
+#endif
+#ifdef AP_UID_MIN
+ fprintf(stderr, " -D AP_UID_MIN=%d\n", AP_UID_MIN);
+#endif
+#ifdef AP_USERDIR_SUFFIX
+ fprintf(stderr, " -D AP_USERDIR_SUFFIX=\"%s\"\n", AP_USERDIR_SUFFIX);
+#endif
+ exit(0);
+ }
+ /*
+ * If there are a proper number of arguments, set
+ * all of them to variables. Otherwise, error out.
+ */
+ if (argc < 4) {
+ log_err("too few arguments\n");
+ exit(101);
+ }
+ target_uname = argv[1];
+ target_gname = argv[2];
+ cmd = argv[3];
+
+ /*
+ * Check to see if the user running this program
+ * is the user allowed to do so as defined in
+ * suexec.h. If not the allowed user, error out.
+ */
+#ifdef _OSD_POSIX
+ /* User name comparisons are case insensitive on BS2000/OSD */
+ if (strcasecmp(AP_HTTPD_USER, pw->pw_name)) {
+ log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER);
+ exit(103);
+ }
+#else /*_OSD_POSIX*/
+ if (strcmp(AP_HTTPD_USER, pw->pw_name)) {
+ log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER);
+ exit(103);
+ }
+#endif /*_OSD_POSIX*/
+
+ /*
+ * Check for a leading '/' (absolute path) in the command to be executed,
+ * or attempts to back up out of the current directory,
+ * to protect against attacks. If any are
+ * found, error out. Naughty naughty crackers.
+ */
+ if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3))
+ || (strstr(cmd, "/../") != NULL)) {
+ log_err("invalid command (%s)\n", cmd);
+ exit(104);
+ }
+
+ /*
+ * Check to see if this is a ~userdir request. If
+ * so, set the flag, and remove the '~' from the
+ * target username.
+ */
+ if (!strncmp("~", target_uname, 1)) {
+ target_uname++;
+ userdir = 1;
+ }
+
+ /*
+ * Error out if the target username is invalid.
+ */
+ if (strspn(target_uname, "1234567890") != strlen(target_uname)) {
+ if ((pw = getpwnam(target_uname)) == NULL) {
+ log_err("invalid target user name: (%s)\n", target_uname);
+ exit(105);
+ }
+ }
+ else {
+ if ((pw = getpwuid(atoi(target_uname))) == NULL) {
+ log_err("invalid target user id: (%s)\n", target_uname);
+ exit(121);
+ }
+ }
+
+ /*
+ * Error out if the target group name is invalid.
+ */
+ if (strspn(target_gname, "1234567890") != strlen(target_gname)) {
+ if ((gr = getgrnam(target_gname)) == NULL) {
+ log_err("invalid target group name: (%s)\n", target_gname);
+ exit(106);
+ }
+ }
+ else {
+ if ((gr = getgrgid(atoi(target_gname))) == NULL) {
+ log_err("invalid target group id: (%s)\n", target_gname);
+ exit(106);
+ }
+ }
+ gid = gr->gr_gid;
+ if ((actual_gname = strdup(gr->gr_name)) == NULL) {
+ log_err("failed to alloc memory\n");
+ exit(125);
+ }
+
+#ifdef _OSD_POSIX
+ /*
+ * Initialize BS2000 user environment
+ */
+ {
+ pid_t pid;
+ int status;
+
+ switch (pid = ufork(target_uname)) {
+ case -1: /* Error */
+ log_err("failed to setup bs2000 environment for user %s: %s\n",
+ target_uname, strerror(errno));
+ exit(150);
+ case 0: /* Child */
+ break;
+ default: /* Father */
+ while (pid != waitpid(pid, &status, 0))
+ ;
+ /* @@@ FIXME: should we deal with STOP signals as well? */
+ if (WIFSIGNALED(status)) {
+ kill (getpid(), WTERMSIG(status));
+ }
+ exit(WEXITSTATUS(status));
+ }
+ }
+#endif /*_OSD_POSIX*/
+
+ /*
+ * Save these for later since initgroups will hose the struct
+ */
+ uid = pw->pw_uid;
+ actual_uname = strdup(pw->pw_name);
+ target_homedir = strdup(pw->pw_dir);
+ if (actual_uname == NULL || target_homedir == NULL) {
+ log_err("failed to alloc memory\n");
+ exit(126);
+ }
+
+ /*
+ * Log the transaction here to be sure we have an open log
+ * before we setuid().
+ */
+ log_no_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n",
+ target_uname, actual_uname,
+ target_gname, actual_gname,
+ cmd);
+
+ /*
+ * Error out if attempt is made to execute as root or as
+ * a UID less than AP_UID_MIN. Tsk tsk.
+ */
+ if ((uid == 0) || (uid < AP_UID_MIN)) {
+ log_err("cannot run as forbidden uid (%lu/%s)\n", (unsigned long)uid, cmd);
+ exit(107);
+ }
+
+ /*
+ * Error out if attempt is made to execute as root group
+ * or as a GID less than AP_GID_MIN. Tsk tsk.
+ */
+ if ((gid == 0) || (gid < AP_GID_MIN)) {
+ log_err("cannot run as forbidden gid (%lu/%s)\n", (unsigned long)gid, cmd);
+ exit(108);
+ }
+
+ /*
+ * Change UID/GID here so that the following tests work over NFS.
+ *
+ * Initialize the group access list for the target user,
+ * and setgid() to the target group. If unsuccessful, error out.
+ */
+ if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) {
+ log_err("failed to setgid/initgroups (%lu: %s): %s\n",
+ (unsigned long)gid, cmd, strerror(errno));
+ exit(109);
+ }
+
+ /*
+ * setuid() to the target user. Error out on fail.
+ */
+ if ((setuid(uid)) != 0) {
+ log_err("failed to setuid (%lu: %s): %s\n",
+ (unsigned long)uid, cmd, strerror(errno));
+ exit(110);
+ }
+
+ /*
+ * Get the current working directory, as well as the proper
+ * document root (dependent upon whether or not it is a
+ * ~userdir request). Error out if we cannot get either one,
+ * or if the current working directory is not in the docroot.
+ * Use chdir()s and getcwd()s to avoid problems with symlinked
+ * directories. Yuck.
+ */
+ if (getcwd(cwd, AP_MAXPATH) == NULL) {
+ log_err("cannot get current working directory\n");
+ exit(111);
+ }
+
+ if (userdir) {
+ if (((chdir(target_homedir)) != 0) ||
+ ((chdir(AP_USERDIR_SUFFIX)) != 0) ||
+ ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+ ((chdir(cwd)) != 0)) {
+ log_err("cannot get docroot information (%s)\n", target_homedir);
+ exit(112);
+ }
+ }
+ else {
+ if (((chdir(AP_DOC_ROOT)) != 0) ||
+ ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+ ((chdir(cwd)) != 0)) {
+ log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT);
+ exit(113);
+ }
+ }
+
+ if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
+ log_err("command not in docroot (%s/%s)\n", cwd, cmd);
+ exit(114);
+ }
+
+ /*
+ * Stat the cwd and verify it is a directory, or error out.
+ */
+ if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) {
+ log_err("cannot stat directory: (%s)\n", cwd);
+ exit(115);
+ }
+
+ /*
+ * Error out if cwd is writable by others.
+ */
+ if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
+ log_err("directory is writable by others: (%s)\n", cwd);
+ exit(116);
+ }
+
+ /*
+ * Error out if we cannot stat the program.
+ */
+ if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
+ log_err("cannot stat program: (%s)\n", cmd);
+ exit(117);
+ }
+
+ /*
+ * Error out if the program is writable by others.
+ */
+ if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
+ log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
+ exit(118);
+ }
+
+ /*
+ * Error out if the file is setuid or setgid.
+ */
+ if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) {
+ log_err("file is either setuid or setgid: (%s/%s)\n", cwd, cmd);
+ exit(119);
+ }
+
+ /*
+ * Error out if the target name/group is different from
+ * the name/group of the cwd or the program.
+ */
+ if ((uid != dir_info.st_uid) ||
+ (gid != dir_info.st_gid) ||
+ (uid != prg_info.st_uid) ||
+ (gid != prg_info.st_gid)) {
+ log_err("target uid/gid (%lu/%lu) mismatch "
+ "with directory (%lu/%lu) or program (%lu/%lu)\n",
+ (unsigned long)uid, (unsigned long)gid,
+ (unsigned long)dir_info.st_uid, (unsigned long)dir_info.st_gid,
+ (unsigned long)prg_info.st_uid, (unsigned long)prg_info.st_gid);
+ exit(120);
+ }
+ /*
+ * Error out if the program is not executable for the user.
+ * Otherwise, she won't find any error in the logs except for
+ * "[error] Premature end of script headers: ..."
+ */
+ if (!(prg_info.st_mode & S_IXUSR)) {
+ log_err("file has no execute permission: (%s/%s)\n", cwd, cmd);
+ exit(121);
+ }
+
+#ifdef AP_SUEXEC_UMASK
+ /*
+ * umask() uses inverse logic; bits are CLEAR for allowed access.
+ */
+ if ((~AP_SUEXEC_UMASK) & 0022) {
+ log_err("notice: AP_SUEXEC_UMASK of %03o allows "
+ "write permission to group and/or other\n", AP_SUEXEC_UMASK);
+ }
+ umask(AP_SUEXEC_UMASK);
+#endif /* AP_SUEXEC_UMASK */
+
+ /* Be sure to close the log file so the CGI can't mess with it. */
+#ifdef AP_LOG_SYSLOG
+ if (log_open) {
+ closelog();
+ log_open = 0;
+ }
+#else
+ if (log != NULL) {
+#if APR_HAVE_FCNTL_H
+ /*
+ * ask fcntl(2) to set the FD_CLOEXEC flag on the log file,
+ * so it'll be automagically closed if the exec() call succeeds.
+ */
+ fflush(log);
+ setbuf(log, NULL);
+ if ((fcntl(fileno(log), F_SETFD, FD_CLOEXEC) == -1)) {
+ log_err("error: can't set close-on-exec flag");
+ exit(122);
+ }
+#else
+ /*
+ * In this case, exec() errors won't be logged because we have already
+ * dropped privileges and won't be able to reopen the log file.
+ */
+ fclose(log);
+ log = NULL;
+#endif
+ }
+#endif
+
+ /*
+ * Execute the command, replacing our image with its own.
+ */
+#ifdef NEED_HASHBANG_EMUL
+ /* We need the #! emulation when we want to execute scripts */
+ {
+ extern char **environ;
+
+ ap_execve(cmd, &argv[3], environ);
+ }
+#else /*NEED_HASHBANG_EMUL*/
+ execv(cmd, &argv[3]);
+#endif /*NEED_HASHBANG_EMUL*/
+
+ /*
+ * (I can't help myself...sorry.)
+ *
+ * Uh oh. Still here. Where's the kaboom? There was supposed to be an
+ * EARTH-shattering kaboom!
+ *
+ * Oh well, log the failure and error out.
+ */
+ log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd);
+ exit(255);
+}
diff --git a/support/suexec.h b/support/suexec.h
new file mode 100644
index 0000000..07bb7bb
--- /dev/null
+++ b/support/suexec.h
@@ -0,0 +1,109 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file suexec.h
+ * @brief user-definable variables for the suexec wrapper code.
+ * (See README.configure on how to customize these variables.)
+ */
+
+
+#ifndef _SUEXEC_H
+#define _SUEXEC_H
+
+/*
+ * Include ap_config_layout so we can work out where the default htdocsdir
+ * and logsdir are.
+ */
+#include "ap_config_layout.h"
+
+/*
+ * HTTPD_USER -- Define as the username under which Apache normally
+ * runs. This is the only user allowed to execute
+ * this program.
+ */
+#ifndef AP_HTTPD_USER
+#define AP_HTTPD_USER "www"
+#endif
+
+/*
+ * UID_MIN -- Define this as the lowest UID allowed to be a target user
+ * for suEXEC. For most systems, 500 or 100 is common.
+ */
+#ifndef AP_UID_MIN
+#define AP_UID_MIN 100
+#endif
+
+/*
+ * GID_MIN -- Define this as the lowest GID allowed to be a target group
+ * for suEXEC. For most systems, 100 is common.
+ */
+#ifndef AP_GID_MIN
+#define AP_GID_MIN 100
+#endif
+
+/*
+ * USERDIR_SUFFIX -- Define to be the subdirectory under users'
+ * home directories where suEXEC access should
+ * be allowed. All executables under this directory
+ * will be executable by suEXEC as the user so
+ * they should be "safe" programs. If you are
+ * using a "simple" UserDir directive (ie. one
+ * without a "*" in it) this should be set to
+ * the same value. suEXEC will not work properly
+ * in cases where the UserDir directive points to
+ * a location that is not the same as the user's
+ * home directory as referenced in the passwd file.
+ *
+ * If you have VirtualHosts with a different
+ * UserDir for each, you will need to define them to
+ * all reside in one parent directory; then name that
+ * parent directory here. IF THIS IS NOT DEFINED
+ * PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK!
+ * See the suEXEC documentation for more detailed
+ * information.
+ */
+#ifndef AP_USERDIR_SUFFIX
+#define AP_USERDIR_SUFFIX "public_html"
+#endif
+
+/*
+ * LOG_EXEC -- Define this as a filename if you want all suEXEC
+ * transactions and errors logged for auditing and
+ * debugging purposes.
+ */
+#ifndef AP_LOG_EXEC
+#define AP_LOG_EXEC DEFAULT_EXP_LOGFILEDIR "/suexec_log" /* Need me? */
+#endif
+
+/*
+ * DOC_ROOT -- Define as the DocumentRoot set for Apache. This
+ * will be the only hierarchy (aside from UserDirs)
+ * that can be used for suEXEC behavior.
+ */
+#ifndef AP_DOC_ROOT
+#define AP_DOC_ROOT DEFAULT_EXP_HTDOCSDIR
+#endif
+
+/*
+ * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables.
+ *
+ */
+#ifndef AP_SAFE_PATH
+#define AP_SAFE_PATH "/usr/local/bin:/usr/bin:/bin"
+#endif
+
+#endif /* _SUEXEC_H */
diff --git a/support/win32/ApacheMonitor.c b/support/win32/ApacheMonitor.c
new file mode 100644
index 0000000..841b4ab
--- /dev/null
+++ b/support/win32/ApacheMonitor.c
@@ -0,0 +1,1671 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* ====================================================================
+ * ApacheMonitor.c Simple program to manage and monitor Apache services.
+ *
+ * Contributed by Mladen Turk <mturk mappingsoft.com>
+ *
+ * 05 Aug 2001
+ * ====================================================================
+ */
+
+#define _WIN32_WINNT 0x0500
+#ifndef STRICT
+#define STRICT
+#endif
+#ifndef OEMRESOURCE
+#define OEMRESOURCE
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+#include <objbase.h>
+#include <shlobj.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <WtsApi32.h>
+#include <tchar.h>
+#include "ApacheMonitor.h"
+
+#ifndef AM_STRINGIFY
+/** Properly quote a value as a string in the C preprocessor */
+#define AM_STRINGIFY(n) AM_STRINGIFY_HELPER(n)
+/** Helper macro for AM_STRINGIFY */
+#define AM_STRINGIFY_HELPER(n) #n
+#endif
+
+#define OS_VERSION_WINNT 2
+#define OS_VERSION_WIN2K 3
+
+/* Should be enough */
+#define MAX_APACHE_SERVICES 128
+#define MAX_APACHE_COMPUTERS 32
+
+#define WM_TRAYMESSAGE (WM_APP+1)
+#define WM_UPDATEMESSAGE (WM_USER+1)
+#define WM_MANAGEMESSAGE (WM_USER+2)
+#define WM_TIMER_REFRESH 10
+#define WM_TIMER_RESCAN 11
+#define SERVICE_APACHE_RESTART 128
+#define XBITMAP 16
+#define YBITMAP 16
+#define MAX_LOADSTRING 100
+#define REFRESH_TIME 2000 /* service refresh time (ms) */
+#define RESCAN_TIME 20000 /* registry rescan time (ms) */
+
+typedef struct _st_APACHE_SERVICE
+{
+ LPTSTR szServiceName;
+ LPTSTR szDisplayName;
+ LPTSTR szDescription;
+ LPTSTR szImagePath;
+ LPTSTR szComputerName;
+ DWORD dwPid;
+} ST_APACHE_SERVICE;
+
+typedef struct _st_MONITORED_COMPUTERS
+{
+ LPTSTR szComputerName;
+ HKEY hRegistry;
+} ST_MONITORED_COMP;
+
+/* Global variables */
+HINSTANCE g_hInstance = NULL;
+TCHAR *g_szTitle; /* The title bar text */
+TCHAR *g_szWindowClass; /* Window Class Name */
+HICON g_icoStop;
+HICON g_icoRun;
+UINT g_bUiTaskbarCreated;
+DWORD g_dwOSVersion;
+BOOL g_bDlgServiceOn = FALSE;
+BOOL g_bConsoleRun = FALSE;
+ST_APACHE_SERVICE g_stServices[MAX_APACHE_SERVICES];
+ST_MONITORED_COMP g_stComputers[MAX_APACHE_COMPUTERS];
+
+HBITMAP g_hBmpStart, g_hBmpStop;
+HBITMAP g_hBmpPicture, g_hBmpOld;
+BOOL g_bRescanServices;
+HWND g_hwndServiceDlg;
+HWND g_hwndMain;
+HWND g_hwndStdoutList;
+HWND g_hwndConnectDlg;
+HCURSOR g_hCursorHourglass;
+HCURSOR g_hCursorArrow;
+
+LANGID g_LangID;
+CRITICAL_SECTION g_stcSection;
+LPTSTR g_szLocalHost;
+
+/* locale language support */
+static TCHAR *g_lpMsg[IDS_MSG_LAST - IDS_MSG_FIRST + 1];
+
+
+void am_ClearServicesSt()
+{
+ int i;
+ for (i = 0; i < MAX_APACHE_SERVICES; i++)
+ {
+ if (g_stServices[i].szServiceName) {
+ free(g_stServices[i].szServiceName);
+ }
+ if (g_stServices[i].szDisplayName) {
+ free(g_stServices[i].szDisplayName);
+ }
+ if (g_stServices[i].szDescription) {
+ free(g_stServices[i].szDescription);
+ }
+ if (g_stServices[i].szImagePath) {
+ free(g_stServices[i].szImagePath);
+ }
+ if (g_stServices[i].szComputerName) {
+ free(g_stServices[i].szComputerName);
+ }
+
+ }
+ memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
+
+}
+
+
+void am_ClearComputersSt()
+{
+ int i;
+ for (i = 0; i < MAX_APACHE_COMPUTERS; i++) {
+ if (g_stComputers[i].szComputerName) {
+ free(g_stComputers[i].szComputerName);
+ RegCloseKey(g_stComputers[i].hRegistry);
+ }
+ }
+ memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
+
+}
+
+
+BOOL am_IsComputerConnected(LPTSTR szComputerName)
+{
+ int i = 0;
+ while (g_stComputers[i].szComputerName != NULL) {
+ if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
+ return TRUE;
+ }
+ ++i;
+ }
+ return FALSE;
+}
+
+
+void am_DisconnectComputer(LPTSTR szComputerName)
+{
+ int i = 0, j;
+ while (g_stComputers[i].szComputerName != NULL) {
+ if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
+ break;
+ }
+ ++i;
+ }
+ if (g_stComputers[i].szComputerName != NULL) {
+ free(g_stComputers[i].szComputerName);
+ RegCloseKey(g_stComputers[i].hRegistry);
+ for (j = i; j < MAX_APACHE_COMPUTERS - 1; j++) {
+ g_stComputers[j].szComputerName= g_stComputers[j+1].szComputerName;
+ g_stComputers[j].hRegistry = g_stComputers[j+1].hRegistry;
+ }
+ g_stComputers[j].szComputerName = NULL;
+ g_stComputers[j].hRegistry = NULL;
+ }
+}
+
+
+void ErrorMessage(LPCTSTR szError, BOOL bFatal)
+{
+ LPVOID lpMsgBuf = NULL;
+ if (szError) {
+ MessageBox(NULL, szError, g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST],
+ MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION));
+ }
+ else {
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), g_LangID,
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+ MessageBox(NULL, (LPCTSTR)lpMsgBuf,
+ g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST],
+ MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION));
+ LocalFree(lpMsgBuf);
+ }
+ if (bFatal) {
+ PostQuitMessage(0);
+ }
+}
+
+
+int am_RespawnAsUserAdmin(HWND hwnd, DWORD op, LPCTSTR szService,
+ LPCTSTR szComputerName)
+{
+ TCHAR args[MAX_PATH + MAX_COMPUTERNAME_LENGTH + 12];
+
+ if (g_dwOSVersion < OS_VERSION_WIN2K) {
+ ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], FALSE);
+ return 0;
+ }
+
+ _sntprintf(args, sizeof(args) / sizeof(TCHAR),
+ _T("%d \"%s\" \"%s\""), op, szService,
+ szComputerName ? szComputerName : _T(""));
+ if (!ShellExecute(hwnd, _T("runas"), __targv[0], args, NULL, SW_NORMAL)) {
+ ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+ FALSE);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+BOOL am_ConnectComputer(LPTSTR szComputerName)
+{
+ int i = 0;
+ HKEY hKeyRemote;
+ TCHAR szTmp[MAX_PATH];
+
+ while (g_stComputers[i].szComputerName != NULL) {
+ if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
+ return FALSE;
+ }
+ ++i;
+ }
+ if (i > MAX_APACHE_COMPUTERS - 1) {
+ return FALSE;
+ }
+ if (RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyRemote)
+ != ERROR_SUCCESS) {
+ _sntprintf(szTmp, sizeof(szTmp) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_ECONNECT - IDS_MSG_FIRST],
+ szComputerName);
+ ErrorMessage(szTmp, FALSE);
+ return FALSE;
+ }
+ else {
+ g_stComputers[i].szComputerName = _tcsdup(szComputerName);
+ g_stComputers[i].hRegistry = hKeyRemote;
+ return TRUE;
+ }
+}
+
+
+LPTSTR GetStringRes(int id)
+{
+ static TCHAR buffer[MAX_PATH];
+
+ buffer[0] = 0;
+ LoadString(GetModuleHandle(NULL), id, buffer, MAX_PATH);
+ return buffer;
+}
+
+
+BOOL GetSystemOSVersion(LPDWORD dwVersion)
+{
+ OSVERSIONINFO osvi;
+ /*
+ Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+ If that fails, try using the OSVERSIONINFO structure.
+ */
+ memset(&osvi, 0, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ if (!GetVersionEx(&osvi)) {
+ return FALSE;
+ }
+
+ switch (osvi.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_NT:
+ if (osvi.dwMajorVersion >= 5)
+ *dwVersion = OS_VERSION_WIN2K;
+ else
+ *dwVersion = OS_VERSION_WINNT;
+ break;
+
+ case VER_PLATFORM_WIN32_WINDOWS:
+ case VER_PLATFORM_WIN32s:
+ default:
+ *dwVersion = 0;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static VOID ShowNotifyIcon(HWND hWnd, DWORD dwMessage)
+{
+ NOTIFYICONDATA nid;
+ int i = 0, n = 0;
+
+ memset(&nid, 0, sizeof(nid));
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hWnd;
+ nid.uID = 0xFF;
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_TRAYMESSAGE;
+
+ while (g_stServices[i].szServiceName != NULL)
+ {
+ if (g_stServices[i].dwPid != 0) {
+ ++n;
+ }
+ ++i;
+ }
+ if (dwMessage != NIM_DELETE)
+ {
+ if (n) {
+ nid.hIcon = g_icoRun;
+ }
+ else {
+ nid.hIcon = g_icoStop;
+ }
+ }
+ else {
+ nid.hIcon = NULL;
+ }
+ if (n == i && n > 0) {
+ _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_RUNNINGALL - IDS_MSG_FIRST]);
+ }
+ else if (n) {
+ _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_RUNNING - IDS_MSG_FIRST], n, i);
+ }
+ else if (i) {
+ _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_RUNNINGNONE - IDS_MSG_FIRST], i);
+ }
+ else {
+ _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_NOSERVICES - IDS_MSG_FIRST]);
+ }
+ Shell_NotifyIcon(dwMessage, &nid);
+}
+
+
+void appendMenuItem(HMENU hMenu, UINT uMenuId, LPTSTR szName,
+ BOOL fDefault, BOOL fEnabled)
+{
+ MENUITEMINFO mii;
+
+ memset(&mii, 0, sizeof(MENUITEMINFO));
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
+ if (_tcslen(szName))
+ {
+ mii.fType = MFT_STRING;
+ mii.wID = uMenuId;
+ if (fDefault) {
+ mii.fState = MFS_DEFAULT;
+ }
+ if (!fEnabled) {
+ mii.fState |= MFS_DISABLED;
+ }
+ mii.dwTypeData = szName;
+ }
+ else {
+ mii.fType = MFT_SEPARATOR;
+ }
+ InsertMenuItem(hMenu, uMenuId, FALSE, &mii);
+}
+
+
+void appendServiceMenu(HMENU hMenu, UINT uMenuId,
+ LPTSTR szServiceName, BOOL fRunning)
+{
+ MENUITEMINFO mii;
+ HMENU smh;
+
+ smh = CreatePopupMenu();
+
+ appendMenuItem(smh, IDM_SM_START + uMenuId,
+ g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST], FALSE, !fRunning);
+ appendMenuItem(smh, IDM_SM_STOP + uMenuId,
+ g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST], FALSE, fRunning);
+ appendMenuItem(smh, IDM_SM_RESTART + uMenuId,
+ g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST], FALSE, fRunning);
+
+ memset(&mii, 0, sizeof(MENUITEMINFO));
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU
+ | MIIM_CHECKMARKS;
+ mii.fType = MFT_STRING;
+ mii.wID = uMenuId;
+ mii.hbmpChecked = g_hBmpStart;
+ mii.hbmpUnchecked = g_hBmpStop;
+ mii.dwTypeData = szServiceName;
+ mii.hSubMenu = smh;
+ mii.fState = fRunning ? MFS_CHECKED : MFS_UNCHECKED;
+ InsertMenuItem(hMenu, IDM_SM_SERVICE + uMenuId, FALSE, &mii);
+}
+
+
+void ShowTryPopupMenu(HWND hWnd)
+{
+ /* create popup menu */
+ HMENU hMenu = CreatePopupMenu();
+ POINT pt;
+
+ if (hMenu)
+ {
+ appendMenuItem(hMenu, IDM_RESTORE,
+ g_lpMsg[IDS_MSG_MNUSHOW - IDS_MSG_FIRST],
+ TRUE, TRUE);
+ appendMenuItem(hMenu, IDC_SMANAGER,
+ g_lpMsg[IDS_MSG_MNUSERVICES - IDS_MSG_FIRST],
+ FALSE, TRUE);
+ appendMenuItem(hMenu, 0, _T(""), FALSE, TRUE);
+ appendMenuItem(hMenu, IDM_EXIT,
+ g_lpMsg[IDS_MSG_MNUEXIT - IDS_MSG_FIRST],
+ FALSE, TRUE);
+
+ if (!SetForegroundWindow(hWnd)) {
+ SetForegroundWindow(NULL);
+ }
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON,
+ pt.x, pt.y, 0, hWnd, NULL);
+ DestroyMenu(hMenu);
+ }
+}
+
+
+void ShowTryServicesMenu(HWND hWnd)
+{
+ /* create services list popup menu and submenus */
+ HMENU hMenu = CreatePopupMenu();
+ POINT pt;
+ int i = 0;
+
+ if (hMenu)
+ {
+ while (g_stServices[i].szServiceName != NULL)
+ {
+ appendServiceMenu(hMenu, i, g_stServices[i].szDisplayName,
+ g_stServices[i].dwPid != 0);
+ ++i;
+ }
+ if (i)
+ {
+ if (!SetForegroundWindow(hWnd)) {
+ SetForegroundWindow(NULL);
+ }
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON,
+ pt.x, pt.y, 0, hWnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ }
+}
+
+
+BOOL CenterWindow(HWND hwndChild)
+{
+ RECT rChild, rWorkArea;
+ int wChild, hChild;
+ int xNew, yNew;
+ BOOL bResult;
+
+ /* Get the Height and Width of the child window */
+ GetWindowRect(hwndChild, &rChild);
+ wChild = rChild.right - rChild.left;
+ hChild = rChild.bottom - rChild.top;
+
+ /* Get the limits of the 'workarea' */
+ bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT),
+ &rWorkArea, 0);
+ if (!bResult) {
+ rWorkArea.left = rWorkArea.top = 0;
+ rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
+ rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
+ }
+
+ /* Calculate new X and Y position*/
+ xNew = (rWorkArea.right - wChild) / 2;
+ yNew = (rWorkArea.bottom - hChild) / 2;
+ return SetWindowPos(hwndChild, HWND_TOP, xNew, yNew, 0, 0,
+ SWP_NOSIZE | SWP_SHOWWINDOW);
+}
+
+
+static void addListBoxItem(HWND hDlg, LPTSTR lpStr, HBITMAP hBmp)
+{
+ LRESULT nItem;
+
+ nItem = SendMessage(hDlg, LB_ADDSTRING, 0, (LPARAM)lpStr);
+ SendMessage(hDlg, LB_SETITEMDATA, nItem, (LPARAM)hBmp);
+}
+
+
+static void addListBoxString(HWND hListBox, LPTSTR lpStr)
+{
+ static int nItems = 0;
+ if (!g_bDlgServiceOn) {
+ return;
+ }
+ ++nItems;
+ if (nItems > MAX_LOADSTRING)
+ {
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+ nItems = 1;
+ }
+ ListBox_SetCurSel(hListBox,
+ ListBox_AddString(hListBox, lpStr));
+
+}
+
+
+BOOL ApacheManageService(LPCTSTR szServiceName, LPCTSTR szImagePath,
+ LPTSTR szComputerName, DWORD dwCommand)
+{
+ TCHAR szMsg[MAX_PATH];
+ BOOL retValue;
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+ SERVICE_STATUS schSStatus;
+ int ticks;
+
+ schSCManager = OpenSCManager(szComputerName, NULL,
+ SC_MANAGER_CONNECT);
+ if (!schSCManager) {
+ ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+ FALSE);
+ return FALSE;
+ }
+
+ schService = OpenService(schSCManager, szServiceName,
+ SERVICE_QUERY_STATUS | SERVICE_START |
+ SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL);
+ if (schService == NULL)
+ {
+ /* Avoid recursion of ImagePath NULL (from this Respawn) */
+ if (szImagePath) {
+ am_RespawnAsUserAdmin(g_hwndMain, dwCommand,
+ szServiceName, szComputerName);
+ }
+ else {
+ ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+ FALSE);
+ }
+ CloseServiceHandle(schSCManager);
+ return FALSE;
+ }
+ else
+ {
+ retValue = FALSE;
+ g_bConsoleRun = TRUE;
+ SetCursor(g_hCursorHourglass);
+ switch (dwCommand)
+ {
+ case SERVICE_CONTROL_STOP:
+ _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_SRVSTOP - IDS_MSG_FIRST],
+ szServiceName);
+ addListBoxString(g_hwndStdoutList, szMsg);
+ if (ControlService(schService, SERVICE_CONTROL_STOP,
+ &schSStatus)) {
+ Sleep(1000);
+ while (QueryServiceStatus(schService, &schSStatus))
+ {
+ if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING)
+ {
+ Sleep(1000);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ if (QueryServiceStatus(schService, &schSStatus))
+ {
+ if (schSStatus.dwCurrentState == SERVICE_STOPPED)
+ {
+ retValue = TRUE;
+ _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_SRVSTOPPED - IDS_MSG_FIRST],
+ szServiceName);
+ addListBoxString(g_hwndStdoutList, szMsg);
+ }
+ }
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_SRVSTART - IDS_MSG_FIRST],
+ szServiceName);
+ addListBoxString(g_hwndStdoutList, szMsg);
+
+ if (StartService(schService, 0, NULL))
+ {
+ Sleep(1000);
+ while (QueryServiceStatus(schService, &schSStatus))
+ {
+ if (schSStatus.dwCurrentState == SERVICE_START_PENDING)
+ {
+ Sleep(1000);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ if (QueryServiceStatus(schService, &schSStatus))
+ {
+ if (schSStatus.dwCurrentState == SERVICE_RUNNING)
+ {
+ retValue = TRUE;
+ _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_SRVSTARTED - IDS_MSG_FIRST],
+ szServiceName);
+ addListBoxString(g_hwndStdoutList, szMsg);
+ }
+ }
+ break;
+
+ case SERVICE_APACHE_RESTART:
+ _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_SRVRESTART - IDS_MSG_FIRST],
+ szServiceName);
+ addListBoxString(g_hwndStdoutList, szMsg);
+ if (ControlService(schService, SERVICE_APACHE_RESTART,
+ &schSStatus))
+ {
+ ticks = 60;
+ while (schSStatus.dwCurrentState == SERVICE_START_PENDING)
+ {
+ Sleep(1000);
+ if (!QueryServiceStatus(schService, &schSStatus))
+ {
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ g_bConsoleRun = FALSE;
+ SetCursor(g_hCursorArrow);
+ return FALSE;
+ }
+ if (!--ticks) {
+ break;
+ }
+ }
+ }
+ if (schSStatus.dwCurrentState == SERVICE_RUNNING)
+ {
+ retValue = TRUE;
+ _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+ g_lpMsg[IDS_MSG_SRVRESTARTED - IDS_MSG_FIRST],
+ szServiceName);
+ addListBoxString(g_hwndStdoutList, szMsg);
+ }
+ break;
+ }
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ if (!retValue) {
+ ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+ FALSE);
+ }
+ g_bConsoleRun = FALSE;
+ SetCursor(g_hCursorArrow);
+ return retValue;
+ }
+ return FALSE;
+}
+
+
+BOOL IsServiceRunning(LPCTSTR szServiceName, LPCTSTR szComputerName,
+ LPDWORD lpdwPid)
+{
+ DWORD dwPid;
+ SC_HANDLE schService;
+ SC_HANDLE schSCManager;
+ SERVICE_STATUS schSStatus;
+
+ dwPid = 0;
+ schSCManager = OpenSCManager(szComputerName, NULL,
+ SC_MANAGER_CONNECT);
+ if (!schSCManager) {
+ return FALSE;
+ }
+
+ schService = OpenService(schSCManager, szServiceName,
+ SERVICE_QUERY_STATUS);
+ if (schService != NULL)
+ {
+ if (QueryServiceStatus(schService, &schSStatus))
+ {
+ dwPid = schSStatus.dwCurrentState;
+ if (lpdwPid) {
+ *lpdwPid = 1;
+ }
+ }
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return dwPid == SERVICE_RUNNING ? TRUE : FALSE;
+ }
+ else {
+ g_bRescanServices = TRUE;
+ }
+ CloseServiceHandle(schSCManager);
+ return FALSE;
+}
+
+
+BOOL FindRunningServices(void)
+{
+ int i = 0;
+ DWORD dwPid;
+ BOOL rv = FALSE;
+ while (g_stServices[i].szServiceName != NULL)
+ {
+ if (!IsServiceRunning(g_stServices[i].szServiceName,
+ g_stServices[i].szComputerName, &dwPid)) {
+ dwPid = 0;
+ }
+ if (g_stServices[i].dwPid != dwPid) {
+ rv = TRUE;
+ }
+ g_stServices[i].dwPid = dwPid;
+ ++i;
+ }
+ return rv;
+}
+
+
+BOOL GetApacheServicesStatus()
+{
+ TCHAR szKey[MAX_PATH];
+ TCHAR achKey[MAX_PATH];
+ TCHAR szImagePath[MAX_PATH];
+ TCHAR szBuf[MAX_PATH];
+ TCHAR szTmp[MAX_PATH];
+ HKEY hKey, hSubKey, hKeyRemote;
+ DWORD retCode, rv, dwKeyType;
+ DWORD dwBufLen = MAX_PATH;
+ int i, stPos = 0;
+ int computers = 0;
+
+ g_bRescanServices = FALSE;
+
+ am_ClearServicesSt();
+ while (g_stComputers[computers].szComputerName != NULL) {
+ hKeyRemote = g_stComputers[computers].hRegistry;
+ retCode = RegOpenKeyEx(hKeyRemote,
+ _T("System\\CurrentControlSet\\Services\\"),
+ 0, KEY_READ, &hKey);
+ if (retCode != ERROR_SUCCESS)
+ {
+ ErrorMessage(NULL, FALSE);
+ return FALSE;
+ }
+ for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
+ {
+ retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);
+ if (retCode == ERROR_SUCCESS)
+ {
+ _tcscpy(szKey, _T("System\\CurrentControlSet\\Services\\"));
+ _tcscat(szKey, achKey);
+
+ if (RegOpenKeyEx(hKeyRemote, szKey, 0,
+ KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
+ {
+ dwBufLen = MAX_PATH;
+ rv = RegQueryValueEx(hSubKey, _T("ImagePath"), NULL,
+ &dwKeyType, (LPBYTE)szImagePath, &dwBufLen);
+
+ if (rv == ERROR_SUCCESS
+ && (dwKeyType == REG_SZ
+ || dwKeyType == REG_EXPAND_SZ)
+ && dwBufLen)
+ {
+ _tcscpy(szBuf, szImagePath);
+ CharLower(szBuf);
+ /* the service name could be httpd*.exe or Apache*.exe */
+ if (((_tcsstr(szBuf, _T("\\apache")) != NULL)
+ || (_tcsstr(szBuf, _T("\\httpd")) != NULL))
+ && _tcsstr(szBuf, _T(".exe"))
+ && (_tcsstr(szBuf, _T("--ntservice")) != NULL
+ || _tcsstr(szBuf, _T("-k ")) != NULL))
+ {
+ g_stServices[stPos].szServiceName = _tcsdup(achKey);
+ g_stServices[stPos].szImagePath = _tcsdup(szImagePath);
+ g_stServices[stPos].szComputerName =
+ _tcsdup(g_stComputers[computers].szComputerName);
+ dwBufLen = MAX_PATH;
+ if (RegQueryValueEx(hSubKey, _T("Description"), NULL,
+ &dwKeyType, (LPBYTE)szBuf, &dwBufLen)
+ == ERROR_SUCCESS) {
+ g_stServices[stPos].szDescription = _tcsdup(szBuf);
+ }
+ dwBufLen = MAX_PATH;
+ if (RegQueryValueEx(hSubKey, _T("DisplayName"), NULL,
+ &dwKeyType, (LPBYTE)szBuf, &dwBufLen)
+ == ERROR_SUCCESS)
+ {
+ if (_tcscmp(g_stComputers[computers]
+ .szComputerName, g_szLocalHost) != 0)
+ {
+ _tcscpy(szTmp, g_stComputers[computers]
+ .szComputerName + 2);
+ _tcscat(szTmp, _T("@"));
+ _tcscat(szTmp, szBuf);
+ }
+ else {
+ _tcscpy(szTmp, szBuf);
+ }
+ g_stServices[stPos].szDisplayName = _tcsdup(szTmp);
+
+ }
+ ++stPos;
+ if (stPos >= MAX_APACHE_SERVICES) {
+ retCode = !ERROR_SUCCESS;
+ }
+ }
+ }
+ RegCloseKey(hSubKey);
+ }
+ }
+ }
+ ++computers;
+ RegCloseKey(hKey);
+ }
+ FindRunningServices();
+ return TRUE;
+}
+
+
+LRESULT CALLBACK ConnectDlgProc(HWND hDlg, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ ShowWindow(hDlg, SW_HIDE);
+ g_hwndConnectDlg = hDlg;
+ CenterWindow(hDlg);
+ ShowWindow(hDlg, SW_SHOW);
+ SetFocus(GetDlgItem(hDlg, IDC_COMPUTER));
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ memset(szCmp, 0, sizeof(szCmp));
+ _tcscpy(szCmp, _T("\\\\"));
+ SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), WM_GETTEXT,
+ (WPARAM) MAX_COMPUTERNAME_LENGTH,
+ (LPARAM) szCmp+2);
+
+ _tcsupr(szCmp);
+ if (_tcslen(szCmp) < 3) {
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+ }
+ am_ConnectComputer(szCmp);
+ SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
+
+ case IDCANCEL:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ case IDC_LBROWSE:
+ {
+ BROWSEINFO bi;
+ ITEMIDLIST *il;
+ LPMALLOC pMalloc;
+ memset(&bi, 0, sizeof(BROWSEINFO));
+ SHGetSpecialFolderLocation(hDlg, CSIDL_NETWORK, &il);
+
+ bi.lpszTitle = _T("ApacheMonitor :\nSelect Network Computer!");
+ bi.pszDisplayName = szCmp;
+ bi.hwndOwner = hDlg;
+ bi.ulFlags = BIF_BROWSEFORCOMPUTER;
+ bi.lpfn = NULL;
+ bi.lParam = 0;
+ bi.iImage = 0;
+ bi.pidlRoot = il;
+
+ if (SHBrowseForFolder(&bi) != NULL) {
+ SendMessage(GetDlgItem(hDlg, IDC_COMPUTER),
+ WM_SETTEXT,
+ (WPARAM) NULL, (LPARAM) szCmp);
+ }
+ if (SUCCEEDED(SHGetMalloc(&pMalloc))) {
+ pMalloc->lpVtbl->Free(pMalloc, il);
+ pMalloc->lpVtbl->Release(pMalloc);
+ }
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_QUIT:
+ case WM_CLOSE:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+ return FALSE;
+
+}
+
+
+LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ TCHAR szBuf[MAX_PATH];
+ HWND hListBox;
+ static HWND hStatusBar;
+ TEXTMETRIC tm;
+ int i, y;
+ HDC hdcMem;
+ RECT rcBitmap;
+ LRESULT nItem;
+ LPMEASUREITEMSTRUCT lpmis;
+ LPDRAWITEMSTRUCT lpdis;
+
+ memset(szBuf, 0, sizeof(szBuf));
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ ShowWindow(hDlg, SW_HIDE);
+ g_hwndServiceDlg = hDlg;
+ SetWindowText(hDlg, g_szTitle);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
+ SetWindowText(GetDlgItem(hDlg, IDC_SSTART),
+ g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST]);
+ SetWindowText(GetDlgItem(hDlg, IDC_SSTOP),
+ g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST]);
+ SetWindowText(GetDlgItem(hDlg, IDC_SRESTART),
+ g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST]);
+ SetWindowText(GetDlgItem(hDlg, IDC_SMANAGER),
+ g_lpMsg[IDS_MSG_SERVICES - IDS_MSG_FIRST]);
+ SetWindowText(GetDlgItem(hDlg, IDC_SCONNECT),
+ g_lpMsg[IDS_MSG_CONNECT - IDS_MSG_FIRST]);
+ SetWindowText(GetDlgItem(hDlg, IDCANCEL),
+ g_lpMsg[IDS_MSG_OK - IDS_MSG_FIRST]);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ g_hwndStdoutList = GetDlgItem(hDlg, IDL_STDOUT);
+ hStatusBar = CreateStatusWindow(0x0800 /* SBT_TOOLTIPS */
+ | WS_CHILD | WS_VISIBLE,
+ _T(""), hDlg, IDC_STATBAR);
+ if (GetApacheServicesStatus())
+ {
+ i = 0;
+ while (g_stServices[i].szServiceName != NULL)
+ {
+ addListBoxItem(hListBox, g_stServices[i].szDisplayName,
+ g_stServices[i].dwPid == 0 ? g_hBmpStop
+ : g_hBmpStart);
+ ++i;
+ }
+ }
+ CenterWindow(hDlg);
+ ShowWindow(hDlg, SW_SHOW);
+ SetFocus(hListBox);
+ SendMessage(hListBox, LB_SETCURSEL, 0, 0);
+ return TRUE;
+ break;
+
+ case WM_MANAGEMESSAGE:
+ ApacheManageService(g_stServices[LOWORD(wParam)].szServiceName,
+ g_stServices[LOWORD(wParam)].szImagePath,
+ g_stServices[LOWORD(wParam)].szComputerName,
+ LOWORD(lParam));
+
+ return TRUE;
+ break;
+
+ case WM_UPDATEMESSAGE:
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+ SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
+ i = 0;
+ while (g_stServices[i].szServiceName != NULL)
+ {
+ addListBoxItem(hListBox, g_stServices[i].szDisplayName,
+ g_stServices[i].dwPid == 0 ? g_hBmpStop : g_hBmpStart);
+ ++i;
+ }
+ SendMessage(hListBox, LB_SETCURSEL, 0, 0);
+ /* Dirty hack to bring the window to the foreground */
+ SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetFocus(hListBox);
+ return TRUE;
+ break;
+
+ case WM_MEASUREITEM:
+ lpmis = (LPMEASUREITEMSTRUCT) lParam;
+ lpmis->itemHeight = YBITMAP;
+ return TRUE;
+
+ case WM_SETCURSOR:
+ if (g_bConsoleRun) {
+ SetCursor(g_hCursorHourglass);
+ }
+ else {
+ SetCursor(g_hCursorArrow);
+ }
+ return TRUE;
+
+ case WM_DRAWITEM:
+ lpdis = (LPDRAWITEMSTRUCT) lParam;
+ if (lpdis->itemID == -1) {
+ break;
+ }
+ switch (lpdis->itemAction)
+ {
+ case ODA_FOCUS:
+ case ODA_SELECT:
+ case ODA_DRAWENTIRE:
+ g_hBmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem,
+ LB_GETITEMDATA,
+ lpdis->itemID, (LPARAM) 0);
+
+ hdcMem = CreateCompatibleDC(lpdis->hDC);
+ g_hBmpOld = SelectObject(hdcMem, g_hBmpPicture);
+
+ BitBlt(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
+ lpdis->rcItem.right - lpdis->rcItem.left,
+ lpdis->rcItem.bottom - lpdis->rcItem.top,
+ hdcMem, 0, 0, SRCCOPY);
+ SendMessage(lpdis->hwndItem, LB_GETTEXT,
+ lpdis->itemID, (LPARAM) szBuf);
+
+ GetTextMetrics(lpdis->hDC, &tm);
+ y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
+
+ SelectObject(hdcMem, g_hBmpOld);
+ DeleteDC(hdcMem);
+
+ rcBitmap.left = lpdis->rcItem.left + XBITMAP + 2;
+ rcBitmap.top = lpdis->rcItem.top;
+ rcBitmap.right = lpdis->rcItem.right;
+ rcBitmap.bottom = lpdis->rcItem.top + YBITMAP;
+
+ if (lpdis->itemState & ODS_SELECTED)
+ {
+ if (g_hBmpPicture == g_hBmpStop)
+ {
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
+ Button_SetStyle(GetDlgItem(hDlg, IDC_SSTART), BS_DEFPUSHBUTTON, TRUE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ }
+ else if (g_hBmpPicture == g_hBmpStart)
+ {
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
+ Button_SetStyle(GetDlgItem(hDlg, IDC_SSTOP), BS_DEFPUSHBUTTON, TRUE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
+ }
+ else {
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ }
+ if (_tcscmp(g_stServices[lpdis->itemID].szComputerName,
+ g_szLocalHost) == 0) {
+ Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
+ }
+ else {
+ Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), TRUE);
+ }
+
+ if (g_stServices[lpdis->itemID].szDescription) {
+ SendMessage(hStatusBar, SB_SETTEXT, 0,
+ (LPARAM)g_stServices[lpdis->itemID].szDescription);
+ }
+ else {
+ SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
+ }
+ if (lpdis->itemState & ODS_FOCUS) {
+ SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
+ FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHT+1));
+ }
+ else {
+ SetTextColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTIONTEXT));
+ SetBkColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTION));
+ FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_INACTIVECAPTION+1));
+ }
+ }
+ else
+ {
+ SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT));
+ SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
+ FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1));
+ }
+ TextOut(lpdis->hDC, XBITMAP + 6, y, szBuf, (int)_tcslen(szBuf));
+ break;
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDL_SERVICES:
+ switch (HIWORD(wParam))
+ {
+ case LBN_DBLCLK:
+ /* if started then stop, if stopped then start */
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR)
+ {
+ g_hBmpPicture = (HBITMAP)SendMessage(hListBox,
+ LB_GETITEMDATA,
+ nItem, (LPARAM) 0);
+ if (g_hBmpPicture == g_hBmpStop) {
+ SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+ SERVICE_CONTROL_CONTINUE);
+ }
+ else {
+ SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+ SERVICE_CONTROL_STOP);
+ }
+
+ }
+ return TRUE;
+ }
+ break;
+
+ case IDCANCEL:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ case IDC_SSTART:
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR) {
+ SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+ SERVICE_CONTROL_CONTINUE);
+ }
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
+ return TRUE;
+
+ case IDC_SSTOP:
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR) {
+ SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+ SERVICE_CONTROL_STOP);
+ }
+ Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
+ return TRUE;
+
+ case IDC_SRESTART:
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR) {
+ SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+ SERVICE_APACHE_RESTART);
+ }
+ Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
+ return TRUE;
+
+ case IDC_SMANAGER:
+ if (g_dwOSVersion >= OS_VERSION_WIN2K) {
+ ShellExecute(hDlg, _T("open"), _T("services.msc"), _T("/s"),
+ NULL, SW_NORMAL);
+ }
+ else {
+ WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
+ }
+ return TRUE;
+
+ case IDC_SCONNECT:
+ DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGCONNECT),
+ hDlg, (DLGPROC)ConnectDlgProc);
+ return TRUE;
+
+ case IDC_SDISCONN:
+ hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+ nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+ if (nItem != LB_ERR) {
+ am_DisconnectComputer(g_stServices[nItem].szComputerName);
+ SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
+ }
+ return TRUE;
+ }
+ break;
+
+ case WM_SIZE:
+ switch (LOWORD(wParam))
+ {
+ case SIZE_MINIMIZED:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+ break;
+ }
+ break;
+
+ case WM_QUIT:
+ case WM_CLOSE:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ if (message == g_bUiTaskbarCreated)
+ {
+ /* restore the tray icon on shell restart */
+ ShowNotifyIcon(hWnd, NIM_ADD);
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ switch (message)
+ {
+ case WM_CREATE:
+ GetApacheServicesStatus();
+ ShowNotifyIcon(hWnd, NIM_ADD);
+ SetTimer(hWnd, WM_TIMER_REFRESH, REFRESH_TIME, NULL);
+ SetTimer(hWnd, WM_TIMER_RESCAN, RESCAN_TIME, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case WM_TIMER_RESCAN:
+ {
+ int nPrev = 0, nNew = 0;
+ EnterCriticalSection(&g_stcSection);
+ if (FindRunningServices() || g_bRescanServices)
+ {
+ ShowNotifyIcon(hWnd, NIM_MODIFY);
+ if (g_hwndServiceDlg)
+ PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+ }
+ /* check if services list changed */
+ while (g_stServices[nPrev].szServiceName != NULL)
+ ++nPrev;
+ GetApacheServicesStatus();
+ while (g_stServices[nNew].szServiceName != NULL)
+ ++nNew;
+ if (nPrev != nNew)
+ {
+ ShowNotifyIcon(hWnd, NIM_MODIFY);
+ if (g_hwndServiceDlg) {
+ PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+ }
+ }
+ LeaveCriticalSection(&g_stcSection);
+ break;
+ }
+
+ case WM_TIMER_REFRESH:
+ {
+ EnterCriticalSection(&g_stcSection);
+ if (g_bRescanServices)
+ {
+ GetApacheServicesStatus();
+ ShowNotifyIcon(hWnd, NIM_MODIFY);
+ if (g_hwndServiceDlg) {
+ PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+ }
+ }
+ else if (FindRunningServices())
+ {
+ ShowNotifyIcon(hWnd, NIM_MODIFY);
+ if (g_hwndServiceDlg) {
+ PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+ }
+ }
+ LeaveCriticalSection(&g_stcSection);
+ break;
+ }
+ }
+ break;
+
+ case WM_QUIT:
+ ShowNotifyIcon(hWnd, NIM_DELETE);
+ break;
+
+ case WM_TRAYMESSAGE:
+ switch (lParam)
+ {
+ case WM_LBUTTONDBLCLK:
+ if (!g_bDlgServiceOn)
+ {
+ g_bDlgServiceOn = TRUE;
+ DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
+ hWnd, (DLGPROC)ServiceDlgProc);
+ g_bDlgServiceOn = FALSE;
+ g_hwndServiceDlg = NULL;
+ }
+ else if (IsWindow(g_hwndServiceDlg))
+ {
+ /* Dirty hack to bring the window to the foreground */
+ SetWindowPos(g_hwndServiceDlg, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetWindowPos(g_hwndServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ SetFocus(g_hwndServiceDlg);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ ShowTryServicesMenu(hWnd);
+ break;
+
+ case WM_RBUTTONUP:
+ ShowTryPopupMenu(hWnd);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ if ((LOWORD(wParam) & IDM_SM_START) == IDM_SM_START)
+ {
+ ApacheManageService(g_stServices[LOWORD(wParam)
+ - IDM_SM_START].szServiceName,
+ g_stServices[LOWORD(wParam)
+ - IDM_SM_START].szImagePath,
+ g_stServices[LOWORD(wParam)
+ - IDM_SM_START].szComputerName,
+ SERVICE_CONTROL_CONTINUE);
+ return TRUE;
+ }
+ else if ((LOWORD(wParam) & IDM_SM_STOP) == IDM_SM_STOP)
+ {
+ ApacheManageService(g_stServices[LOWORD(wParam)
+ - IDM_SM_STOP].szServiceName,
+ g_stServices[LOWORD(wParam)
+ - IDM_SM_STOP].szImagePath,
+ g_stServices[LOWORD(wParam)
+ - IDM_SM_STOP].szComputerName,
+ SERVICE_CONTROL_STOP);
+ return TRUE;
+ }
+ else if ((LOWORD(wParam) & IDM_SM_RESTART) == IDM_SM_RESTART)
+ {
+ ApacheManageService(g_stServices[LOWORD(wParam)
+ - IDM_SM_RESTART].szServiceName,
+ g_stServices[LOWORD(wParam)
+ - IDM_SM_RESTART].szImagePath,
+ g_stServices[LOWORD(wParam)
+ - IDM_SM_RESTART].szComputerName,
+ SERVICE_APACHE_RESTART);
+ return TRUE;
+ }
+ switch (LOWORD(wParam))
+ {
+ case IDM_RESTORE:
+ if (!g_bDlgServiceOn)
+ {
+ g_bDlgServiceOn = TRUE;
+ DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
+ hWnd, (DLGPROC)ServiceDlgProc);
+ g_bDlgServiceOn = FALSE;
+ g_hwndServiceDlg = NULL;
+ }
+ else if (IsWindow(g_hwndServiceDlg)) {
+ SetFocus(g_hwndServiceDlg);
+ }
+ break;
+
+ case IDC_SMANAGER:
+ if (g_dwOSVersion >= OS_VERSION_WIN2K) {
+ ShellExecute(NULL, _T("open"), _T("services.msc"), _T("/s"),
+ NULL, SW_NORMAL);
+ }
+ else {
+ WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
+ }
+ return TRUE;
+
+ case IDM_EXIT:
+ ShowNotifyIcon(hWnd, NIM_DELETE);
+ PostQuitMessage(0);
+ return TRUE;
+ }
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ return FALSE;
+}
+
+
+static int KillAWindow(HWND appwindow)
+{
+ HANDLE appproc;
+ DWORD procid;
+ BOOL postres;
+
+ SetLastError(0);
+ GetWindowThreadProcessId(appwindow, &procid);
+ if (GetLastError())
+ return(2);
+
+ appproc = OpenProcess(SYNCHRONIZE, 0, procid);
+ postres = PostMessage(appwindow, WM_COMMAND, IDM_EXIT, 0);
+ if (appproc && postres) {
+ if (WaitForSingleObject(appproc, 10 /* seconds */ * 1000)
+ == WAIT_OBJECT_0) {
+ CloseHandle(appproc);
+ return (0);
+ }
+ }
+ if (appproc)
+ CloseHandle(appproc);
+
+ if ((appproc = OpenProcess(PROCESS_TERMINATE, 0, procid)) != NULL) {
+ if (TerminateProcess(appproc, 0)) {
+ CloseHandle(appproc);
+ return (0);
+ }
+ CloseHandle(appproc);
+ }
+
+ /* Perhaps we were short of permissions? */
+ return (2);
+}
+
+
+static int KillAllMonitors(void)
+{
+ HWND appwindow;
+ int exitcode = 0;
+ PWTS_PROCESS_INFO tsProcs;
+ DWORD tsProcCount, i;
+ DWORD thisProcId;
+
+ /* This is graceful, close our own Window, clearing the icon */
+ if ((appwindow = FindWindow(g_szWindowClass, g_szTitle)) != NULL)
+ exitcode = KillAWindow(appwindow);
+
+ if (g_dwOSVersion < OS_VERSION_WIN2K)
+ return exitcode;
+
+ thisProcId = GetCurrentProcessId();
+
+ if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1,
+ &tsProcs, &tsProcCount))
+ return exitcode;
+
+ /* This is ungraceful; close other Windows, with a lingering icon.
+ * Since on terminal server it's not possible to post the message
+ * to exit across sessions, we have to suffer this side effect
+ * of a taskbar 'icon' which will evaporate the next time that
+ * the user hovers over it or when the taskbar area is updated.
+ */
+ for (i = 0; i < tsProcCount; ++i) {
+ if (_tcscmp(tsProcs[i].pProcessName, _T(AM_STRINGIFY(BIN_NAME))) == 0
+ && tsProcs[i].ProcessId != thisProcId)
+ WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE,
+ tsProcs[i].ProcessId, 1);
+ }
+ WTSFreeMemory(tsProcs);
+ return exitcode;
+}
+
+
+/* Create main invisible window */
+HWND CreateMainWindow(HINSTANCE hInstance)
+{
+ HWND hWnd = NULL;
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
+ IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
+ wcex.hCursor = g_hCursorArrow;
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = g_szWindowClass;
+ wcex.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
+ IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+
+ if (RegisterClassEx(&wcex)) {
+ hWnd = CreateWindow(g_szWindowClass, g_szTitle,
+ 0, 0, 0, 0, 0,
+ NULL, NULL, hInstance, NULL);
+ }
+ return hWnd;
+}
+
+
+#ifndef UNICODE
+/* Borrowed from CRT internal.h for _MBCS argc/argv parsing in this GUI app */
+int __cdecl _setargv(void);
+#endif
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine, int nCmdShow)
+{
+ TCHAR szTmp[MAX_LOADSTRING];
+ TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
+ MSG msg;
+ /* existing window */
+ HWND appwindow;
+ DWORD dwControl;
+ int i;
+ DWORD d;
+
+ if (!GetSystemOSVersion(&g_dwOSVersion))
+ {
+ ErrorMessage(NULL, TRUE);
+ return 1;
+ }
+
+ g_LangID = GetUserDefaultLangID();
+ if ((g_LangID & 0xFF) != LANG_ENGLISH) {
+ g_LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
+ }
+ for (i = IDS_MSG_FIRST; i <= IDS_MSG_LAST; ++i) {
+ LoadString(hInstance, i, szTmp, MAX_LOADSTRING);
+ g_lpMsg[i - IDS_MSG_FIRST] = _tcsdup(szTmp);
+ }
+ LoadString(hInstance, IDS_APMONITORTITLE, szTmp, MAX_LOADSTRING);
+ d = MAX_COMPUTERNAME_LENGTH+1;
+ _tcscpy(szCmp, _T("\\\\"));
+ GetComputerName(szCmp + 2, &d);
+ _tcsupr(szCmp);
+ g_szLocalHost = _tcsdup(szCmp);
+
+ memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
+ g_stComputers[0].szComputerName = _tcsdup(szCmp);
+ g_stComputers[0].hRegistry = HKEY_LOCAL_MACHINE;
+ g_szTitle = _tcsdup(szTmp);
+ LoadString(hInstance, IDS_APMONITORCLASS, szTmp, MAX_LOADSTRING);
+ g_szWindowClass = _tcsdup(szTmp);
+
+ appwindow = FindWindow(g_szWindowClass, g_szTitle);
+
+#ifdef UNICODE
+ __wargv = CommandLineToArgvW(GetCommandLineW(), &__argc);
+#else
+#if defined(_MSC_VER) && _MSC_VER < 1800
+ _setargv();
+#endif
+#endif
+
+ if ((__argc == 2) && (_tcscmp(__targv[1], _T("--kill")) == 0))
+ {
+ /* Off to chase and close up every ApacheMonitor taskbar window */
+ return KillAllMonitors();
+ }
+ else if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K))
+ {
+ dwControl = _ttoi(__targv[1]);
+ if ((dwControl != SERVICE_CONTROL_CONTINUE) &&
+ (dwControl != SERVICE_APACHE_RESTART) &&
+ (dwControl != SERVICE_CONTROL_STOP))
+ {
+ return 1;
+ }
+
+ /* Chase down and close up our session's previous window */
+ if ((appwindow) != NULL)
+ KillAWindow(appwindow);
+ }
+ else if (__argc != 1) {
+ return 1;
+ }
+ else if (appwindow)
+ {
+ ErrorMessage(g_lpMsg[IDS_MSG_APPRUNNING - IDS_MSG_FIRST], FALSE);
+ return 0;
+ }
+
+ g_icoStop = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP),
+ IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+ g_icoRun = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICORUN),
+ IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+ g_hCursorHourglass = LoadImage(NULL, MAKEINTRESOURCE(OCR_WAIT),
+ IMAGE_CURSOR, LR_DEFAULTSIZE,
+ LR_DEFAULTSIZE, LR_SHARED);
+ g_hCursorArrow = LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL),
+ IMAGE_CURSOR, LR_DEFAULTSIZE,
+ LR_DEFAULTSIZE, LR_SHARED);
+ g_hBmpStart = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPRUN),
+ IMAGE_BITMAP, XBITMAP, YBITMAP,
+ LR_DEFAULTCOLOR);
+ g_hBmpStop = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPSTOP),
+ IMAGE_BITMAP, XBITMAP, YBITMAP,
+ LR_DEFAULTCOLOR);
+
+ memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
+ CoInitialize(NULL);
+ InitCommonControls();
+ g_hInstance = hInstance;
+ g_hwndMain = CreateMainWindow(hInstance);
+ g_bUiTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
+ InitializeCriticalSection(&g_stcSection);
+ g_hwndServiceDlg = NULL;
+ if (g_hwndMain != NULL)
+ {
+ /* To avoid recursion, pass ImagePath NULL (a noop on NT and later) */
+ if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K))
+ ApacheManageService(__targv[2], NULL, __targv[3], dwControl);
+
+ while (GetMessage(&msg, NULL, 0, 0) == TRUE)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ am_ClearServicesSt();
+ }
+ am_ClearComputersSt();
+ DeleteCriticalSection(&g_stcSection);
+ DestroyIcon(g_icoStop);
+ DestroyIcon(g_icoRun);
+ DestroyCursor(g_hCursorHourglass);
+ DestroyCursor(g_hCursorArrow);
+ DeleteObject(g_hBmpStart);
+ DeleteObject(g_hBmpStop);
+ CoUninitialize();
+ return 0;
+}
+
diff --git a/support/win32/ApacheMonitor.dep b/support/win32/ApacheMonitor.dep
new file mode 100644
index 0000000..d0eac54
--- /dev/null
+++ b/support/win32/ApacheMonitor.dep
@@ -0,0 +1,18 @@
+# Microsoft Developer Studio Generated Dependency File, included by ApacheMonitor.mak
+
+.\ApacheMonitor.c : \
+ ".\ApacheMonitor.h"\
+
+
+.\ApacheMonitor.rc : \
+ "..\..\build\win32\httpd.rc"\
+ "..\..\include\ap_release.h"\
+ ".\apache_header.bmp"\
+ ".\ApacheMonitor.h"\
+ ".\ApacheMonitor.ico"\
+ ".\ApacheMonitor.manifest"\
+ ".\aprun.ico"\
+ ".\apstop.ico"\
+ ".\srun.bmp"\
+ ".\sstop.bmp"\
+
diff --git a/support/win32/ApacheMonitor.dsp b/support/win32/ApacheMonitor.dsp
new file mode 100644
index 0000000..3465ecd
--- /dev/null
+++ b/support/win32/ApacheMonitor.dsp
@@ -0,0 +1,143 @@
+# Microsoft Developer Studio Project File - Name="ApacheMonitor" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=ApacheMonitor - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ApacheMonitor.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ApacheMonitor.mak" CFG="ApacheMonitor - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ApacheMonitor - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "ApacheMonitor - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /EHsc /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
+# ADD CPP /nologo /MD /W3 /EHsc /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fd"Release/ApacheMonitor_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /i "../../include" /I "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\ApacheMonitor.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
+# ADD CPP /nologo /MDd /W3 /Gm /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fd"Debug/ApacheMonitor_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /i "../../include" /I "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /debug
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\ApacheMonitor.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "ApacheMonitor - Win32 Release"
+# Name "ApacheMonitor - Win32 Debug"
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\apache_header.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\aprun.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\apstop.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\srun.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstop.bmp
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ApacheMonitor.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/win32/ApacheMonitor.h b/support/win32/ApacheMonitor.h
new file mode 100644
index 0000000..87109aa
--- /dev/null
+++ b/support/win32/ApacheMonitor.h
@@ -0,0 +1,78 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ApacheMonitor.h
+ * @brief Resource definitions for ApacheMonitor.rc and ApacheMonitor.c
+ */
+#define BIN_NAME ApacheMonitor.exe
+
+#define IDD_DLGSERVICES 101
+#define IDS_APMONITORTITLE 102
+#define IDS_APMONITORCLASS 103
+#define IDM_RESTORE 104
+#define IDM_EXIT 105
+#define IDI_APSRVMON 106
+#define IDI_ICOSTOP 107
+#define IDI_ICORUN 108
+#define IDC_STATBAR 109
+#define IDC_SSTATUS 110
+#define IDB_BMPSTOP 111
+#define IDB_BMPRUN 112
+#define IDB_BMPHEADER 114
+#define IDL_SERVICES 115
+#define IDL_STDOUT 116
+#define IDC_SSTART 117
+#define IDC_SSTOP 118
+#define IDC_SRESTART 119
+#define IDC_SMANAGER 121
+#define IDD_DLGCONNECT 122
+#define IDC_LREMOTE 123
+#define IDC_LBROWSE 124
+#define IDC_COMPUTER 125
+#define IDC_SCONNECT 126
+#define IDC_SDISCONN 127
+#define IDS_MSG_FIRST 256
+#define IDS_MSG_APPRUNNING 256
+#define IDS_MSG_ERROR 257
+#define IDS_MSG_RUNNINGALL 258
+#define IDS_MSG_RUNNING 259
+#define IDS_MSG_RUNNINGNONE 260
+#define IDS_MSG_NOSERVICES 261
+#define IDS_MSG_MNUSERVICES 262
+#define IDS_MSG_MNUSHOW 263
+#define IDS_MSG_MNUEXIT 264
+#define IDS_MSG_SRVSTART 265
+#define IDS_MSG_SRVSTARTED 266
+#define IDS_MSG_SRVSTOP 267
+#define IDS_MSG_SRVSTOPPED 268
+#define IDS_MSG_SRVRESTART 269
+#define IDS_MSG_SRVRESTARTED 270
+#define IDS_MSG_SRVFAILED 271
+#define IDS_MSG_SSTART 272
+#define IDS_MSG_SSTOP 273
+#define IDS_MSG_SRESTART 274
+#define IDS_MSG_SERVICES 275
+#define IDS_MSG_CONNECT 276
+#define IDS_MSG_ECONNECT 277
+#define IDS_MSG_OK 278
+#define IDS_MSG_LAST 278
+#define IDM_SM_SERVICE 0x1100
+#define IDM_SM_START 0x1200
+#define IDM_SM_STOP 0x1400
+#define IDM_SM_RESTART 0x1800
+#define IDC_STATIC -1
+
diff --git a/support/win32/ApacheMonitor.ico b/support/win32/ApacheMonitor.ico
new file mode 100644
index 0000000..cd28dc5
--- /dev/null
+++ b/support/win32/ApacheMonitor.ico
Binary files differ
diff --git a/support/win32/ApacheMonitor.mak b/support/win32/ApacheMonitor.mak
new file mode 100644
index 0000000..5143155
--- /dev/null
+++ b/support/win32/ApacheMonitor.mak
@@ -0,0 +1,309 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on ApacheMonitor.dsp
+!IF "$(CFG)" == ""
+CFG=ApacheMonitor - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to ApacheMonitor - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "ApacheMonitor - Win32 Release" && "$(CFG)" != "ApacheMonitor - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ApacheMonitor.mak" CFG="ApacheMonitor - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ApacheMonitor - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "ApacheMonitor - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\ApacheMonitor.obj"
+ -@erase "$(INTDIR)\ApacheMonitor.res"
+ -@erase "$(INTDIR)\ApacheMonitor_src.idb"
+ -@erase "$(INTDIR)\ApacheMonitor_src.pdb"
+ -@erase "$(OUTDIR)\ApacheMonitor.exe"
+ -@erase "$(OUTDIR)\ApacheMonitor.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ApacheMonitor_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ApacheMonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ApacheMonitor.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\ApacheMonitor.pdb" /debug /out:"$(OUTDIR)\ApacheMonitor.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\ApacheMonitor.obj" \
+ "$(INTDIR)\ApacheMonitor.res" \
+ "..\..\srclib\apr\LibR\apr-1.lib" \
+ "..\..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\ApacheMonitor.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\ApacheMonitor.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ApacheMonitor.exe"
+ if exist .\Release\ApacheMonitor.exe.manifest mt.exe -manifest .\Release\ApacheMonitor.exe.manifest -outputresource:.\Release\ApacheMonitor.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\ApacheMonitor.obj"
+ -@erase "$(INTDIR)\ApacheMonitor.res"
+ -@erase "$(INTDIR)\ApacheMonitor_src.idb"
+ -@erase "$(INTDIR)\ApacheMonitor_src.pdb"
+ -@erase "$(OUTDIR)\ApacheMonitor.exe"
+ -@erase "$(OUTDIR)\ApacheMonitor.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Gm /Zi /Od /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ApacheMonitor_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ApacheMonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\ApacheMonitor.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\ApacheMonitor.pdb" /debug /out:"$(OUTDIR)\ApacheMonitor.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\ApacheMonitor.obj" \
+ "$(INTDIR)\ApacheMonitor.res" \
+ "..\..\srclib\apr\LibD\apr-1.lib" \
+ "..\..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\ApacheMonitor.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\ApacheMonitor.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ApacheMonitor.exe"
+ if exist .\Debug\ApacheMonitor.exe.manifest mt.exe -manifest .\Debug\ApacheMonitor.exe.manifest -outputresource:.\Debug\ApacheMonitor.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("ApacheMonitor.dep")
+!INCLUDE "ApacheMonitor.dep"
+!ELSE
+!MESSAGE Warning: cannot find "ApacheMonitor.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release" || "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support\win32"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support\win32"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ENDIF
+
+!IF "$(CFG)" == "ApacheMonitor - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support\win32"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support\win32"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ENDIF
+
+SOURCE=.\ApacheMonitor.c
+
+"$(INTDIR)\ApacheMonitor.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\ApacheMonitor.rc
+
+"$(INTDIR)\ApacheMonitor.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+
+!ENDIF
+
diff --git a/support/win32/ApacheMonitor.manifest b/support/win32/ApacheMonitor.manifest
new file mode 100644
index 0000000..94860b0
--- /dev/null
+++ b/support/win32/ApacheMonitor.manifest
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity version="3.1.0.0" processorArchitecture="*" name="Apache.ApacheMonitor" type="win32" />
+<description>Apache Service Monitor</description>
+<dependency>
+<dependentAssembly>
+<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
+</dependentAssembly>
+</dependency>
+</assembly>
diff --git a/support/win32/ApacheMonitor.rc b/support/win32/ApacheMonitor.rc
new file mode 100644
index 0000000..d4203bf
--- /dev/null
+++ b/support/win32/ApacheMonitor.rc
@@ -0,0 +1,103 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <windows.h>
+
+#include "ApacheMonitor.h"
+
+#define LONG_NAME Apache HTTP Server Monitor
+
+#include "../../build/win32/httpd.rc"
+
+
+IDI_APSRVMON ICON DISCARDABLE "ApacheMonitor.ico"
+IDI_ICOSTOP ICON DISCARDABLE "apstop.ico"
+IDI_ICORUN ICON DISCARDABLE "aprun.ico"
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "ApacheMonitor.manifest"
+
+IDD_DLGSERVICES DIALOGEX 0, 0, 350, 192
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | WS_MINIMIZEBOX | WS_VISIBLE |
+ WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Apache Service Monitor"
+FONT 8, "MS Sans Serif"
+BEGIN
+ PUSHBUTTON "OK",IDCANCEL,298,161,50,14
+ CONTROL IDB_BMPHEADER,IDC_STATIC,"Static",SS_BITMAP,0,0,349,38
+ LTEXT "Service St&atus :",IDC_SSTATUS,3,40,272,8
+ LISTBOX IDL_SERVICES,2,49,285,73,LBS_OWNERDRAWFIXED |
+ LBS_HASSTRINGS | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
+ LISTBOX IDL_STDOUT,2,124,285,51,LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL
+ PUSHBUTTON "&Start",IDC_SSTART,298,49,50,14
+ PUSHBUTTON "S&top",IDC_SSTOP,298,65,50,14
+ PUSHBUTTON "&Restart",IDC_SRESTART,298,81,50,14
+ PUSHBUTTON "Ser&vices",IDC_SMANAGER,298,97,50,14
+ PUSHBUTTON "&Connect",IDC_SCONNECT,298,113,50,14
+ PUSHBUTTON "&Disconnect",IDC_SDISCONN,298,129,50,14
+END
+
+IDD_DLGCONNECT DIALOGEX 0, 0, 240, 54
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | WS_VISIBLE | WS_CLIPCHILDREN |
+ WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Connect To A Remote Computer"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Computer &Name:",IDC_LREMOTE,7,4,155,8
+ EDITTEXT IDC_COMPUTER,7,14,169,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&OK",IDOK,183,14,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,183,34,50,14
+ PUSHBUTTON "&Browse",IDC_LBROWSE,7,34,50,14
+END
+
+IDB_BMPSTOP BITMAP DISCARDABLE "sstop.bmp"
+IDB_BMPRUN BITMAP DISCARDABLE "srun.bmp"
+IDB_BMPHEADER BITMAP DISCARDABLE "apache_header.bmp"
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_APMONITORTITLE "Apache Service Monitor"
+ IDS_APMONITORCLASS "ApacheServiceMonitorClass"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_MSG_APPRUNNING "Apache monitor is already started"
+ IDS_MSG_ERROR "Error"
+ IDS_MSG_RUNNINGALL "Running all Apache services"
+ IDS_MSG_RUNNING "Running %d of %d Apache services"
+ IDS_MSG_RUNNINGNONE "Running none of %d Apache services"
+ IDS_MSG_NOSERVICES "No services installed"
+ IDS_MSG_MNUSERVICES "Open &Services"
+ IDS_MSG_MNUSHOW "&Open Apache Monitor"
+ IDS_MSG_MNUEXIT "E&xit"
+ IDS_MSG_OK "OK"
+ IDS_MSG_SRVSTART "The %s service is starting."
+ IDS_MSG_SRVSTARTED "The %s service has started."
+ IDS_MSG_SRVSTOP "The %s service is stopping."
+ IDS_MSG_SRVSTOPPED "The %s service has stopped."
+ IDS_MSG_SRVRESTART "The %s service is restarting."
+ IDS_MSG_SRVRESTARTED "The %s service has restarted."
+ IDS_MSG_SRVFAILED "The requested operation has failed!"
+ IDS_MSG_SSTART "&Start"
+ IDS_MSG_SSTOP "S&top"
+ IDS_MSG_SRESTART "&Restart"
+ IDS_MSG_SERVICES "Ser&vices"
+ IDS_MSG_CONNECT "&Connect"
+ IDS_MSG_ECONNECT "Unable to connect to the remote registry on %s"
+END
diff --git a/support/win32/apache_header.bmp b/support/win32/apache_header.bmp
new file mode 100644
index 0000000..7340fac
--- /dev/null
+++ b/support/win32/apache_header.bmp
Binary files differ
diff --git a/support/win32/aprun.ico b/support/win32/aprun.ico
new file mode 100644
index 0000000..dbd5832
--- /dev/null
+++ b/support/win32/aprun.ico
Binary files differ
diff --git a/support/win32/apstop.ico b/support/win32/apstop.ico
new file mode 100644
index 0000000..fba49ad
--- /dev/null
+++ b/support/win32/apstop.ico
Binary files differ
diff --git a/support/win32/srun.bmp b/support/win32/srun.bmp
new file mode 100644
index 0000000..90ecd46
--- /dev/null
+++ b/support/win32/srun.bmp
Binary files differ
diff --git a/support/win32/sstop.bmp b/support/win32/sstop.bmp
new file mode 100644
index 0000000..ba73d87
--- /dev/null
+++ b/support/win32/sstop.bmp
Binary files differ
diff --git a/support/win32/wintty.c b/support/win32/wintty.c
new file mode 100644
index 0000000..684ce5b
--- /dev/null
+++ b/support/win32/wintty.c
@@ -0,0 +1,374 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* --------------------------------------------------------------------
+ *
+ * wintty : a Apache/WinNT support utility for monitoring and
+ * reflecting user feedback from the Apache process via
+ * stdin/stdout, even as running within the service context.
+ *
+ * Originally contributed by William Rowe <wrowe covalent.net>
+ *
+ * Note: this implementation is _very_ experimental, and error handling
+ * is far from complete. Using it as a cgi or pipe process allows the
+ * programmer to discover if facilities such as reliable piped logs
+ * are working as expected, or answer operator prompts that would
+ * otherwise be discarded by the service process.
+ *
+ * Also note the isservice detection semantics, which far exceed any
+ * mechanism we have discovered thus far.
+ *
+ * --------------------------------------------------------------------
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define _CRT_SECURE_NO_DEPRECATE
+#pragma warning(disable: 4996)
+#endif
+
+const char *options =
+"\nwintty: a utility for echoing the stdin stream to a new console window,\n"
+"\teven when invoked from within a service (such as the Apache server.)\n"
+"\tAlso reflects the console input back to the stdout stream, allowing\n"
+"\tthe operator to respond to prompts from the context of a service.\n\n"
+"Syntax: %s [opts] [-t \"Window Title\"]\n\n"
+" opts: -c{haracter} or -l{ine} input\n"
+"\t-q{uiet} or -e{cho} input\n"
+"\t-u{nprocessed} or -p{rocessed} input\n"
+"\t-n{owrap} or -w{rap} output lines\n"
+"\t-f{ormatted} or -r{aw} output lines\n"
+"\t-O{output} [number of seconds]\n"
+"\t-v{erbose} error reporting (for debugging)\n"
+"\t-? for this message\n\n";
+
+BOOL verbose = FALSE;
+
+void printerr(char *fmt, ...)
+{
+ char str[1024];
+ va_list args;
+ if (!verbose)
+ return;
+ va_start(args, fmt);
+ wvsprintf(str, fmt, args);
+ OutputDebugString(str);
+}
+
+DWORD WINAPI feedback(LPVOID args);
+
+typedef struct feedback_args_t {
+ HANDLE in;
+ HANDLE out;
+} feedback_args_t;
+
+int main(int argc, char** argv)
+{
+ char str[1024], *contitle = NULL;
+ HANDLE hproc, thread;
+ HANDLE hwinsta = NULL, hsavewinsta;
+ HANDLE hdesk = NULL, hsavedesk = NULL;
+ HANDLE conin, conout;
+ HANDLE hstdin, hstdout, hstderr, hdup;
+ feedback_args_t feed;
+ DWORD conmode;
+ DWORD newinmode = 0, notinmode = 0;
+ DWORD newoutmode = 0, notoutmode = 0;
+ DWORD tid;
+ DWORD len;
+ DWORD timeout = INFINITE;
+ BOOL isservice = FALSE;
+ char *arg0 = argv[0];
+
+ while (--argc) {
+ ++argv;
+ if (**argv == '/' || **argv == '-') {
+ switch (tolower((*argv)[1])) {
+ case 'c':
+ notinmode |= ENABLE_LINE_INPUT; break;
+ case 'l':
+ newinmode |= ENABLE_LINE_INPUT; break;
+ case 'q':
+ notinmode |= ENABLE_ECHO_INPUT; break;
+ case 'e':
+ newinmode |= ENABLE_ECHO_INPUT; break;
+ case 'u':
+ notinmode |= ENABLE_PROCESSED_INPUT; break;
+ case 'p':
+ newinmode |= ENABLE_PROCESSED_INPUT; break;
+ case 'n':
+ notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
+ case 'w':
+ newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break;
+ case 'r':
+ notoutmode |= ENABLE_PROCESSED_OUTPUT; break;
+ case 'f':
+ newoutmode |= ENABLE_PROCESSED_OUTPUT; break;
+ case 'o':
+ if (*(argv + 1) && *(argv + 1)[0] != '-') {
+ *(++argv);
+ timeout = atoi(*argv) / 1000;
+ --argc;
+ }
+ else {
+ timeout = 0;
+ }
+ break;
+ case 'v':
+ verbose = TRUE;
+ break;
+ case 't':
+ contitle = *(++argv);
+ --argc;
+ break;
+ case '?':
+ printf(options, arg0);
+ exit(1);
+ default:
+ printf("wintty option %s not recognized, use -? for help.\n\n", *argv);
+ exit(1);
+ }
+ }
+ else {
+ printf("wintty argument %s not understood, use -? for help.\n\n", *argv);
+ exit(1);
+ }
+ }
+
+ hproc = GetCurrentProcess();
+ hsavewinsta = GetProcessWindowStation();
+ if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) {
+ printerr("GetProcessWindowStation() failed (%d)\n", GetLastError());
+ }
+ else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) {
+ printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n", GetLastError());
+ }
+ else if (strnicmp(str, "Service-", 8) == 0) {
+ printerr("WindowStation Name %s is a service\n", str);
+ isservice = TRUE;
+ }
+ SetLastError(0);
+
+ hstdin = GetStdHandle(STD_INPUT_HANDLE);
+ if (!hstdin || hstdin == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n",
+ GetLastError());
+ }
+ else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0,
+ isservice, DUPLICATE_SAME_ACCESS)) {
+ CloseHandle(hstdin);
+ hstdin = hdup;
+ }
+ else {
+ printerr("DupHandle(stdin [%x]) failed (%d)\n",
+ hstdin, GetLastError());
+ }
+
+ hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n",
+ GetLastError());
+ }
+ else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0,
+ isservice, DUPLICATE_SAME_ACCESS)) {
+ CloseHandle(hstdout);
+ hstdout = hdup;
+ }
+ else {
+ printerr("DupHandle(stdout [%x]) failed (%d)\n",
+ hstdout, GetLastError());
+ }
+
+ hstderr = GetStdHandle(STD_ERROR_HANDLE);
+ if (!hstderr || hstderr == INVALID_HANDLE_VALUE) {
+ printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n",
+ GetLastError());
+ }
+ else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0,
+ isservice, DUPLICATE_SAME_ACCESS)) {
+ CloseHandle(hstderr);
+ hstderr = hdup;
+ }
+ else {
+ printerr("DupHandle(stderr [%x]) failed (%d)\n",
+ hstderr, GetLastError());
+ }
+
+ /* You can't close the console till all the handles above were
+ * rescued by DuplicateHandle()
+ */
+ if (!FreeConsole())
+ printerr("FreeConsole() failed (%d)\n", GetLastError());
+
+ if (isservice) {
+#ifdef WE_EVER_FIGURE_OUT_WHY_THIS_DOESNT_WORK
+ hsavedesk = GetThreadDesktop(GetCurrentThreadId());
+ if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) {
+ printerr("GetThreadDesktop(GetTID()) failed (%d)\n", GetLastError());
+ }
+ CloseWindowStation(hwinsta);
+ hwinsta = OpenWindowStation("WinSta0", TRUE, MAXIMUM_ALLOWED);
+ if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) {
+ printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError());
+ }
+ else if (!SetProcessWindowStation(hwinsta)) {
+ printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError());
+ }
+ hdesk = OpenDesktop("Default", 0, TRUE, MAXIMUM_ALLOWED);
+ if (!hdesk || hdesk == INVALID_HANDLE_VALUE) {
+ printerr("OpenDesktop(Default) failed (%d)\n", GetLastError());
+ }
+ else if (!SetThreadDesktop(hdesk)) {
+ printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError());
+ }
+#else
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ DWORD exitcode = 1;
+ char appbuff[MAX_PATH];
+ char *appname = NULL;
+ char *cmdline = GetCommandLine();
+
+ if (!GetModuleFileName(NULL, appbuff, sizeof(appbuff))) {
+ appname = appbuff;
+ }
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW
+ | STARTF_USESTDHANDLES;
+ si.lpDesktop = "WinSta0\\Default";
+ si.wShowWindow = 1; /* SW_SHOWNORMAL */
+ si.hStdInput = hstdin;
+ si.hStdOutput = hstdout;
+ si.hStdError = hstderr;
+
+ /* Instantly, upon creating the new process, we will close our
+ * copies of the handles so our parent isn't confused when the
+ * child closes their copy of the handle. Without this action,
+ * we would hold a copy of the handle, and the parent would not
+ * receive their EOF notification.
+ */
+ if (CreateProcess(appname, cmdline, NULL, NULL, TRUE,
+ CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
+ NULL, NULL, &si, &pi)) {
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+ ResumeThread(pi.hThread);
+ CloseHandle(pi.hThread);
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ CloseHandle(pi.hProcess);
+ return exitcode;
+ }
+ return 1;
+#endif
+ }
+
+ if (!AllocConsole()) {
+ printerr("AllocConsole(Default) failed (%d)\n", GetLastError());
+ }
+
+ if (contitle && !SetConsoleTitle(contitle)) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+
+ conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FALSE, OPEN_EXISTING, 0, NULL);
+ if (!conout || conout == INVALID_HANDLE_VALUE) {
+ printerr("CreateFile(CONOUT$) failed (%d)\n", GetLastError());
+ }
+ else if (!GetConsoleMode(conout, &conmode)) {
+ printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError());
+ }
+ else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode)
+ & ~notoutmode))) {
+ printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n",
+ conmode, GetLastError());
+ }
+
+ conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FALSE, OPEN_EXISTING, 0, NULL);
+ if (!conin || conin == INVALID_HANDLE_VALUE) {
+ printerr("CreateFile(CONIN$) failed (%d)\n", GetLastError());
+ }
+ else if (!GetConsoleMode(conin, &conmode)) {
+ printerr("GetConsoleMode(CONIN) failed (%d)\n", GetLastError());
+ }
+ else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode)
+ & ~notinmode))) {
+ printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n",
+ conmode, GetLastError());
+ }
+
+ feed.in = conin;
+ feed.out = hstdout;
+ thread = CreateThread(NULL, 0, feedback, (LPVOID)&feed, 0, &tid);
+
+ while (ReadFile(hstdin, str, sizeof(str), &len, NULL))
+ if (!len || !WriteFile(conout, str, len, &len, NULL))
+ break;
+
+ printerr("[EOF] from stdin (%d)\n", GetLastError());
+
+ CloseHandle(stdout);
+ if (!GetConsoleTitle(str, sizeof(str))) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+ else {
+ strcat(str, " - [Finished]");
+ if (!SetConsoleTitle(str)) {
+ printerr("SetConsoleTitle() failed (%d)\n", GetLastError());
+ }
+ }
+
+ WaitForSingleObject(thread, timeout);
+ FreeConsole();
+ if (isservice) {
+ if (!SetProcessWindowStation(hsavewinsta)) {
+ len = GetLastError();
+ }
+ if (!SetThreadDesktop(hsavedesk)) {
+ len = GetLastError();
+ }
+ CloseDesktop(hdesk);
+ CloseWindowStation(hwinsta);
+ }
+ return 0;
+}
+
+
+DWORD WINAPI feedback(LPVOID arg)
+{
+ feedback_args_t *feed = (feedback_args_t*)arg;
+ char *str[1024];
+ DWORD len;
+
+ while (ReadFile(feed->in, str, sizeof(str), &len, NULL))
+ if (!len || !WriteFile(feed->out, str, len, &len, NULL))
+ break;
+
+ printerr("[EOF] from Console (%d)\n", GetLastError());
+
+ return 0;
+}
diff --git a/support/win32/wintty.dep b/support/win32/wintty.dep
new file mode 100644
index 0000000..8f57409
--- /dev/null
+++ b/support/win32/wintty.dep
@@ -0,0 +1,5 @@
+# Microsoft Developer Studio Generated Dependency File, included by wintty.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
diff --git a/support/win32/wintty.dsp b/support/win32/wintty.dsp
new file mode 100644
index 0000000..337ba17
--- /dev/null
+++ b/support/win32/wintty.dsp
@@ -0,0 +1,106 @@
+# Microsoft Developer Studio Project File - Name="wintty" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=wintty - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak" CFG="wintty - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "wintty - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "wintty - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/wintty_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /debug /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\wintty.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/wintty_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug
+# Begin Special Build Tool
+TargetPath=.\Debug\wintty.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "wintty - Win32 Release"
+# Name "wintty - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\wintty.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/support/win32/wintty.mak b/support/win32/wintty.mak
new file mode 100644
index 0000000..d2c3d6c
--- /dev/null
+++ b/support/win32/wintty.mak
@@ -0,0 +1,317 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on wintty.dsp
+!IF "$(CFG)" == ""
+CFG=wintty - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to wintty - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "wintty - Win32 Release" && "$(CFG)" != "wintty - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "wintty.mak" CFG="wintty - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "wintty - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "wintty - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\wintty.obj"
+ -@erase "$(INTDIR)\wintty.res"
+ -@erase "$(INTDIR)\wintty_src.idb"
+ -@erase "$(INTDIR)\wintty_src.pdb"
+ -@erase "$(OUTDIR)\wintty.exe"
+ -@erase "$(OUTDIR)\wintty.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\wintty_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\wintty.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wintty.pdb" /debug /out:"$(OUTDIR)\wintty.exe" /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\wintty.obj" \
+ "$(INTDIR)\wintty.res" \
+ "..\..\srclib\apr\LibR\apr-1.lib" \
+ "..\..\srclib\apr-util\LibR\aprutil-1.lib"
+
+"$(OUTDIR)\wintty.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\wintty.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\wintty.exe"
+ if exist .\Release\wintty.exe.manifest mt.exe -manifest .\Release\wintty.exe.manifest -outputresource:.\Release\wintty.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\wintty.obj"
+ -@erase "$(INTDIR)\wintty.res"
+ -@erase "$(INTDIR)\wintty_src.idb"
+ -@erase "$(INTDIR)\wintty_src.pdb"
+ -@erase "$(OUTDIR)\wintty.exe"
+ -@erase "$(OUTDIR)\wintty.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\wintty_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\wintty.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wintty.pdb" /debug /out:"$(OUTDIR)\wintty.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\wintty.obj" \
+ "$(INTDIR)\wintty.res" \
+ "..\..\srclib\apr\LibD\apr-1.lib" \
+ "..\..\srclib\apr-util\LibD\aprutil-1.lib"
+
+"$(OUTDIR)\wintty.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\wintty.exe
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\wintty.exe"
+ if exist .\Debug\wintty.exe.manifest mt.exe -manifest .\Debug\wintty.exe.manifest -outputresource:.\Debug\wintty.exe;1
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("wintty.dep")
+!INCLUDE "wintty.dep"
+!ELSE
+!MESSAGE Warning: cannot find "wintty.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "wintty - Win32 Release" || "$(CFG)" == "wintty - Win32 Debug"
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+"apr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release"
+ cd "..\..\support\win32"
+
+"apr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+"apr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug"
+ cd "..\..\support\win32"
+
+"apr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ENDIF
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+"aprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release"
+ cd "..\..\support\win32"
+
+"aprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+"aprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"
+ cd "..\..\support\win32"
+
+"aprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\support\win32"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "wintty - Win32 Release"
+
+
+"$(INTDIR)\wintty.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "wintty - Win32 Debug"
+
+
+"$(INTDIR)\wintty.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\wintty.c
+
+"$(INTDIR)\wintty.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+