initial capture of my stuff master
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Sat, 4 Jan 2020 02:36:32 +0000 (13:36 +1100)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Sat, 4 Jan 2020 02:36:32 +0000 (13:36 +1100)
107 files changed:
FILES [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LOG [new file with mode: 0644]
Makefile [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
cgi-bin/printenv [new file with mode: 0755]
cgi-src/Makefile [new file with mode: 0644]
cgi-src/Makefile.in [new file with mode: 0644]
cgi-src/phf.c [new file with mode: 0644]
cgi-src/redirect.8 [new file with mode: 0644]
cgi-src/redirect.c [new file with mode: 0644]
cgi-src/ssi.8 [new file with mode: 0644]
cgi-src/ssi.c [new file with mode: 0644]
config.cache [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.guess.dh-orig [new file with mode: 0755]
config.h [new file with mode: 0644]
config.log [new file with mode: 0644]
config.status [new file with mode: 0755]
config.sub [new file with mode: 0755]
config.sub.dh-orig [new file with mode: 0755]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
contrib/redhat-rpm/thttpd.conf [new file with mode: 0644]
contrib/redhat-rpm/thttpd.init [new file with mode: 0755]
contrib/redhat-rpm/thttpd.spec [new file with mode: 0644]
debian/.debhelper/thttpd/dbgsym-build-ids [new file with mode: 0644]
debian/.debhelper/thttpd/dbgsym-root/DEBIAN/control [new file with mode: 0644]
debian/.debhelper/thttpd/dbgsym-root/DEBIAN/md5sums [new file with mode: 0644]
debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug [new file with mode: 0644]
debian/.debhelper/thttpd/dbgsym-root/usr/share/doc/thttpd-dbgsym [new symlink]
debian/README.Debian [new file with mode: 0644]
debian/README.source [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/debhelper-build-stamp [new file with mode: 0644]
debian/files [new file with mode: 0644]
debian/manpage.1.ex [new file with mode: 0644]
debian/manpage.sgml.ex [new file with mode: 0644]
debian/manpage.xml.ex [new file with mode: 0644]
debian/menu.ex [new file with mode: 0644]
debian/postinst.ex [new file with mode: 0644]
debian/postrm.ex [new file with mode: 0644]
debian/preinst.ex [new file with mode: 0644]
debian/prerm.ex [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/source/format [new file with mode: 0644]
debian/thttpd-docs.docs [new file with mode: 0644]
debian/thttpd.cron.d.ex [new file with mode: 0644]
debian/thttpd.debhelper.log [new file with mode: 0644]
debian/thttpd.default.ex [new file with mode: 0644]
debian/thttpd.doc-base.EX [new file with mode: 0644]
debian/thttpd.substvars [new file with mode: 0644]
debian/thttpd/DEBIAN/control [new file with mode: 0644]
debian/thttpd/DEBIAN/md5sums [new file with mode: 0644]
debian/thttpd/usr/local/man/man8/thttpd.8 [new file with mode: 0644]
debian/thttpd/usr/local/sbin/thttpd [new file with mode: 0755]
debian/thttpd/usr/share/doc/thttpd/README.Debian [new file with mode: 0644]
debian/thttpd/usr/share/doc/thttpd/changelog.Debian.gz [new file with mode: 0644]
debian/thttpd/usr/share/doc/thttpd/copyright [new file with mode: 0644]
debian/watch.ex [new file with mode: 0644]
extras/Makefile [new file with mode: 0644]
extras/Makefile.in [new file with mode: 0644]
extras/htpasswd.1 [new file with mode: 0644]
extras/htpasswd.c [new file with mode: 0644]
extras/makeweb.1 [new file with mode: 0644]
extras/makeweb.c [new file with mode: 0644]
extras/syslogtocern [new file with mode: 0755]
extras/syslogtocern.8 [new file with mode: 0644]
fdwatch.c [new file with mode: 0644]
fdwatch.h [new file with mode: 0644]
fdwatch.o [new file with mode: 0644]
index.html [new file with mode: 0644]
install-sh [new file with mode: 0755]
libhttpd.c [new file with mode: 0644]
libhttpd.h [new file with mode: 0644]
libhttpd.o [new file with mode: 0644]
match.c [new file with mode: 0644]
match.h [new file with mode: 0644]
match.o [new file with mode: 0644]
mime_encodings.h [new file with mode: 0644]
mime_encodings.txt [new file with mode: 0644]
mime_types.h [new file with mode: 0644]
mime_types.txt [new file with mode: 0644]
mmc.c [new file with mode: 0644]
mmc.h [new file with mode: 0644]
mmc.o [new file with mode: 0644]
scripts/500.thttpd-rotate [new file with mode: 0755]
scripts/thttpd.sh [new file with mode: 0755]
scripts/thttpd_wrapper [new file with mode: 0755]
strerror.c [new file with mode: 0644]
tdate_parse.c [new file with mode: 0644]
tdate_parse.h [new file with mode: 0644]
tdate_parse.o [new file with mode: 0644]
thttpd [new file with mode: 0755]
thttpd.8 [new file with mode: 0644]
thttpd.c [new file with mode: 0644]
thttpd.o [new file with mode: 0644]
timers.c [new file with mode: 0644]
timers.h [new file with mode: 0644]
timers.o [new file with mode: 0644]
version.h [new file with mode: 0644]

diff --git a/FILES b/FILES
new file mode 100644 (file)
index 0000000..d43ff22
--- /dev/null
+++ b/FILES
@@ -0,0 +1,51 @@
+FILES
+INSTALL
+Makefile.in
+README
+TODO
+aclocal.m4
+cgi-bin/printenv
+cgi-src/Makefile.in
+cgi-src/redirect.8
+cgi-src/redirect.c
+cgi-src/phf.c
+cgi-src/ssi.8
+cgi-src/ssi.c
+config.guess
+config.h
+config.sub
+configure
+configure.in
+extras/Makefile.in
+extras/htpasswd.1
+extras/htpasswd.c
+extras/makeweb.1
+extras/makeweb.c
+extras/syslogtocern
+extras/syslogtocern.8
+index.html
+install-sh
+libhttpd.c
+libhttpd.h
+match.c
+match.h
+mime_encodings.txt
+mime_types.txt
+mmc.c
+mmc.h
+strerror.c
+tdate_parse.c
+tdate_parse.h
+thttpd.8
+thttpd.c
+fdwatch.c
+fdwatch.h
+timers.c
+timers.h
+version.h
+scripts/500.thttpd-rotate
+scripts/thttpd.sh
+scripts/thttpd_wrapper
+contrib/redhat-rpm/thttpd.spec
+contrib/redhat-rpm/thttpd.init
+contrib/redhat-rpm/thttpd.conf
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..a9c9e9b
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,40 @@
+To build:
+
+    % ./configure
+
+    Edit config.h to change the configuration options if necessary.
+
+    % make
+
+
+To install:
+
+    % make install
+
+    Edit one of your system rc files to run thttpd at boot time.  Do NOT
+    run it from inetd, that setup is inefficient so thttpd doesn't support it.
+
+
+Red Hat:
+
+    On Red Hat Linux systems you can use RPM to install thttpd, like so:
+
+       cd /usr/src/redhat/SOURCES
+       wget http://www.acme.com/software/thttpd/thttpd-2.29.tar.gz
+       rpm -ta thttpd-2.29.tar.gz
+       rpm -i /usr/src/redhat/RPMS/i386/thttpd-2.29-1.i386.rpm
+
+
+Solaris:
+
+    If you're running Solaris and you want to use the security-enhancing
+    chroot feature, then you must create the TCP device files in the chroot
+    tree.  There is no way around this, Solaris needs these files to accept
+    network connections.  You need /dev/tcp, which is a symbolic link like so:
+       /dev/tcp -> ../devices/pseudo/clone@0:tcp
+    And you also need the file it points to:
+       crw-rw-rw-  bin  11, 42 May 24 21:32 /devices/pseudo/clone@0:tcp
+    You probably need some other files too, such as shared libraries and
+    a tmp directory.  Check out the man page for ftpd, it has a big long
+    shell script for setting up an anonymous ftp area that should also
+    work for thttpd.
diff --git a/LOG b/LOG
new file mode 100644 (file)
index 0000000..d3b1a5b
--- /dev/null
+++ b/LOG
@@ -0,0 +1,289 @@
+dpkg-buildpackage: info: source package thttpd
+dpkg-buildpackage: info: source version 2.29-1
+dpkg-buildpackage: info: source distribution unstable
+dpkg-buildpackage: info: source changed by Ralph Ronnquist <ralph.ronnquist@gmail.com>
+ dpkg-source --before-build thttpd-2.29
+dpkg-buildpackage: info: host architecture amd64
+ fakeroot debian/rules clean
+dh clean --with autotools_dev --without systemd
+   dh_testdir
+   dh_auto_clean
+       make -j1 distclean
+make[1]: Entering directory '/home/ralph/src/thttpd/thttpd-2.29'
+for i in  ; do ( \
+    cd $i ; \
+    pwd ; \
+    make -w distclean \
+) ; done
+rm -f thttpd thttpd.o libhttpd.o fdwatch.o mmc.o timers.o match.o tdate_parse.o   mime_encodings.h mime_types.h Makefile config.cache config.log config.status tags
+make[1]: Leaving directory '/home/ralph/src/thttpd/thttpd-2.29'
+   dh_autotools-dev_restoreconfig
+       for c_g in `find . -type f -name config.guess` ; do if test -e "$c_g.dh-orig" ; then mv -f "$c_g.dh-orig" "$c_g" ; fi ; done
+       for c_s in `find . -type f -name config.sub`   ; do if test -e "$c_s.dh-orig" ; then mv -f "$c_s.dh-orig" "$c_s" ; fi ; done
+       find . -type f \( -name config.guess.dh-orig -o -name config.sub.dh-orig \) -delete
+   dh_clean
+       rm -f debian/debhelper-build-stamp
+       rm -f debian/thttpd.substvars
+       rm -f debian/thttpd.*.debhelper
+       rm -rf debian/thttpd/
+       rm -rf debian/.debhelper/
+       rm -f debian/*.debhelper.log
+       rm -f debian/files
+       find .  \( \( \
+               \( -path .\*/.git -o -path .\*/.svn -o -path .\*/.bzr -o -path .\*/.hg -o -path .\*/CVS \) -prune -o -type f -a \
+               \( -name '#*#' -o -name '.*~' -o -name '*~' -o -name DEADJOE \
+                -o -name '*.orig' -o -name '*.rej' -o -name '*.bak' \
+                -o -name '.*.orig' -o -name .*.rej -o -name '.SUMS' \
+                -o -name TAGS -o \( -path '*/.deps/*' -a -name '*.P' \) \
+               \) -exec rm -f {} + \) -o \
+               \( -type d -a -name autom4te.cache -prune -exec rm -rf {} + \) \)
+       rm -f *-stamp
+ debian/rules build
+dh build --with autotools_dev --without systemd
+   dh_testdir
+   dh_update_autotools_config
+   dh_autotools-dev_updateconfig
+       for c_g in `find -type f -name config.guess` ; do if ! test -e "$c_g.dh-orig" ; then mv -f "$c_g" "$c_g.dh-orig" ; cp -f /usr/share/misc/config.guess "$c_g" ; fi ; done
+       for c_s in `find -type f -name config.sub`   ; do if ! test -e "$c_s.dh-orig" ; then mv -f "$c_s" "$c_s.dh-orig" ; cp -f /usr/share/misc/config.sub   "$c_s" ; fi ; done
+   debian/rules override_dh_auto_configure
+make[1]: Entering directory '/home/ralph/src/thttpd/thttpd-2.29'
+dh_auto_configure -- --prefix=/usr/local --mandir=/usr/local/man
+       ./configure --build=x86_64-linux-gnu --prefix=/usr --includedir=\${prefix}/include --mandir=\${prefix}/share/man --infodir=\${prefix}/share/info --sysconfdir=/etc --localstatedir=/var --disable-silent-rules --libdir=\${prefix}/lib/x86_64-linux-gnu --libexecdir=\${prefix}/lib/x86_64-linux-gnu --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr/local --mandir=/usr/local/man
+creating cache ./config.cache
+checking host system type... x86_64-pc-linux-gnu
+checking target system type... x86_64-pc-linux-gnu
+checking build system type... x86_64-pc-linux-gnu
+checking for gcc... gcc
+checking whether the C compiler (gcc -g -O2 ) works... yes
+checking whether the C compiler (gcc -g -O2 ) is a cross-compiler... no
+checking whether we are using GNU C... yes
+checking whether gcc accepts -g... yes
+checking gcc version... 6
+checking how to link static binaries... unknown
+checking for __progname... yes
+checking how to run the C preprocessor... gcc -E
+checking for fcntl.h... yes
+checking for grp.h... yes
+checking for memory.h... yes
+checking for paths.h... yes
+checking for poll.h... yes
+checking for sys/poll.h... yes
+checking for sys/devpoll.h... no
+checking for sys/event.h... no
+checking for osreldate.h... no
+checking whether time.h and sys/time.h may both be included... yes
+checking for dirent.h that defines DIR... yes
+checking for opendir in -ldir... no
+checking for /usr/local/v6/lib... no
+checking for gethostbyname... yes
+checking for socket... yes
+checking for main in -linet6... no
+checking for crypt... no
+checking for crypt in -lcrypt... yes
+checking for hstrerror... yes
+checking for strerror... yes
+checking for waitpid... yes
+checking for vsnprintf... yes
+checking for daemon... yes
+checking for setsid... yes
+checking for setlogin... no
+checking for getaddrinfo... yes
+checking for getnameinfo... yes
+checking for gai_strerror... yes
+checking for kqueue... no
+checking for sigset... yes
+checking for atoll... yes
+checking for unistd.h... yes
+checking for getpagesize... yes
+checking for working mmap... yes
+checking for select... yes
+checking for poll... yes
+checking if struct tm has tm_gmtoff member... yes
+checking if int64_t exists... yes
+checking if socklen_t exists... yes
+checking whether make sets ${MAKE}... yes
+checking for a BSD compatible install... /usr/bin/install -c
+updating cache ./config.cache
+creating ./config.status
+creating Makefile
+creating cgi-src/Makefile
+creating extras/Makefile
+make[1]: Leaving directory '/home/ralph/src/thttpd/thttpd-2.29'
+   dh_auto_build
+       make -j1
+make[1]: Entering directory '/home/ralph/src/thttpd/thttpd-2.29'
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c thttpd.c
+thttpd.c: In function ‘main’:
+thttpd.c:611:12: warning: implicit declaration of function ‘sigset’ [-Wimplicit-function-declaration]
+     (void) sigset( SIGTERM, handle_term );
+            ^~~~~~
+rm -f mime_encodings.h
+sed < mime_encodings.txt > mime_encodings.h \
+  -e 's/#.*//' -e 's/[         ]*$//' -e '/^$/d' \
+  -e 's/[      ][      ]*/", 0, "/' -e 's/^/{ "/' -e 's/$/", 0 },/'
+rm -f mime_types.h
+sed < mime_types.txt > mime_types.h \
+  -e 's/#.*//' -e 's/[         ]*$//' -e '/^$/d' \
+  -e 's/[      ][      ]*/", 0, "/' -e 's/^/{ "/' -e 's/$/", 0 },/'
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c libhttpd.c
+In file included from /usr/include/string.h:630:0,
+                 from /usr/include/memory.h:29,
+                 from libhttpd.c:47:
+libhttpd.c: In function ‘auth_check2’:
+libhttpd.c:1086:15: warning: implicit declaration of function ‘crypt’ [-Wimplicit-function-declaration]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: warning: passing argument 1 of ‘__builtin_strlen’ makes pointer from integer without a cast [-Wint-conversion]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1086:15: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1086:15: warning: passing argument 1 of ‘__builtin_strlen’ makes pointer from integer without a cast [-Wint-conversion]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1086:15: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1086:15: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1086:15: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+  if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+               ^
+libhttpd.c:1086:15: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1135:19: warning: passing argument 1 of ‘__builtin_strlen’ makes pointer from integer without a cast [-Wint-conversion]
+      if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+                   ^
+libhttpd.c:1135:19: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1135:19: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+      if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+                   ^
+libhttpd.c:1135:19: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1135:19: warning: passing argument 1 of ‘__builtin_strlen’ makes pointer from integer without a cast [-Wint-conversion]
+      if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+                   ^
+libhttpd.c:1135:19: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1135:19: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+      if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+                   ^
+libhttpd.c:1135:19: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1135:19: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+      if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+                   ^
+libhttpd.c:1135:19: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c:1135:19: warning: passing argument 1 of ‘__builtin_strcmp’ makes pointer from integer without a cast [-Wint-conversion]
+      if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+                   ^
+libhttpd.c:1135:19: note: expected ‘const char *’ but argument is of type ‘int’
+libhttpd.c: In function ‘cgi_child’:
+libhttpd.c:3557:12: warning: implicit declaration of function ‘sigset’ [-Wimplicit-function-declaration]
+     (void) sigset( SIGPIPE, SIG_DFL );
+            ^~~~~~
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c fdwatch.c
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c mmc.c
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c timers.c
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c match.c
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I. -c tdate_parse.c
+gcc -O2 -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1  -I.  -o thttpd thttpd.o libhttpd.o fdwatch.o mmc.o timers.o match.o tdate_parse.o  -lcrypt  
+for i in  ; do ( \
+    cd $i ; \
+    pwd ; \
+    make -w \
+       WEBDIR=/usr/local/www \
+       CGIBINDIR=/usr/local/www/cgi-bin \
+       MANDIR=/usr/local/man \
+       WEBGROUP=www \
+) ; done
+make[1]: Leaving directory '/home/ralph/src/thttpd/thttpd-2.29'
+   dh_auto_test
+   create-stamp debian/debhelper-build-stamp
+ fakeroot debian/rules binary
+dh binary --with autotools_dev --without systemd
+   create-stamp debian/debhelper-build-stamp
+   dh_testroot
+   dh_prep
+       rm -f debian/thttpd.substvars
+       rm -f debian/thttpd.*.debhelper
+       rm -rf debian/thttpd/
+   dh_auto_install
+       install -d debian/thttpd
+       make -j1 install DESTDIR=/home/ralph/src/thttpd/thttpd-2.29/debian/thttpd AM_UPDATE_INFO_DIR=no
+make[1]: Entering directory '/home/ralph/src/thttpd/thttpd-2.29'
+mkdir -p /home/ralph/src/thttpd/thttpd-2.29/debian/thttpd/usr/local/sbin
+/usr/bin/install -c -m 555 -o bin -g bin thttpd /home/ralph/src/thttpd/thttpd-2.29/debian/thttpd/usr/local/sbin
+mkdir -p /home/ralph/src/thttpd/thttpd-2.29/debian/thttpd/usr/local/man/man8
+/usr/bin/install -c -m 444 -o bin -g bin thttpd.8 /home/ralph/src/thttpd/thttpd-2.29/debian/thttpd/usr/local/man/man8
+make[1]: Leaving directory '/home/ralph/src/thttpd/thttpd-2.29'
+   dh_installdocs
+       install -d debian/thttpd/usr/share/doc/thttpd
+       install -p -m0644 debian/README.Debian debian/thttpd/usr/share/doc/thttpd/README.Debian
+       install -p -m0644 debian/copyright debian/thttpd/usr/share/doc/thttpd/copyright
+   dh_installchangelogs
+       install -p -m0644 debian/changelog debian/thttpd/usr/share/doc/thttpd/changelog.Debian
+   dh_perl
+   dh_link
+   dh_strip_nondeterminism
+   dh_compress
+       cd debian/thttpd
+       chmod a-x usr/share/doc/thttpd/changelog.Debian
+       gzip -9nf usr/share/doc/thttpd/changelog.Debian
+       cd '/home/ralph/src/thttpd/thttpd-2.29'
+   dh_fixperms
+       find debian/thttpd  -print0 2>/dev/null | xargs -0r chown --no-dereference 0:0
+       find debian/thttpd ! -type l  -print0 2>/dev/null | xargs -0r chmod go=rX,u+rw,a-s
+       find debian/thttpd/usr/share/doc -type f  ! -regex 'debian/thttpd/usr/share/doc/[^/]*/examples/.*' -print0 2>/dev/null | xargs -0r chmod 0644
+       find debian/thttpd/usr/share/doc -type d  -print0 2>/dev/null | xargs -0r chmod 0755
+       find debian/thttpd/usr/share/man -type f  -print0 2>/dev/null | xargs -0r chmod 0644
+       find debian/thttpd/usr/include -type f  -print0 2>/dev/null | xargs -0r chmod 0644
+       find debian/thttpd/usr/share/applications -type f  -print0 2>/dev/null | xargs -0r chmod 0644
+       find debian/thttpd/usr/lib/x86_64-linux-gnu/perl5/5.24 debian/thttpd/usr/share/perl5 -type f -perm -5 -name '*.pm'  -print0 2>/dev/null | xargs -0r chmod a-X
+       find debian/thttpd -perm -5 -type f \( -name '*.so.*' -o -name '*.so' -o -name '*.la' -o -name '*.a' -o -name '*.js' -o -name '*.css' -o -name '*.jpeg' -o -name '*.jpg' -o -name '*.png' -o -name '*.gif' -o -name '*.cmxs' \)  -print0 2>/dev/null | xargs -0r chmod 0644
+       find debian/thttpd/usr/lib -type f -name '*.ali'  -print0 2>/dev/null | xargs -0r chmod uga-w
+   dh_strip
+       install -d debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16
+       objcopy --only-keep-debug --compress-debug-sections debian/thttpd/usr/local/sbin/thttpd debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug
+       chmod 0644 -- debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug
+       chown 0:0 -- debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug
+       strip --remove-section=.comment --remove-section=.note debian/thttpd/usr/local/sbin/thttpd
+       objcopy --add-gnu-debuglink debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug debian/thttpd/usr/local/sbin/thttpd
+       install -d debian/.debhelper/thttpd/dbgsym-root/usr/share/doc
+       ln -s thttpd debian/.debhelper/thttpd/dbgsym-root/usr/share/doc/thttpd-dbgsym
+   dh_makeshlibs
+       rm -f debian/thttpd/DEBIAN/shlibs
+   dh_shlibdeps
+       install -d debian/thttpd/DEBIAN
+       dpkg-shlibdeps -Tdebian/thttpd.substvars debian/thttpd/usr/local/sbin/thttpd
+   dh_installdeb
+   dh_gencontrol
+       echo misc:Depends= >> debian/thttpd.substvars
+       echo misc:Pre-Depends= >> debian/thttpd.substvars
+       install -d debian/.debhelper/thttpd/dbgsym-root/DEBIAN
+       dpkg-gencontrol -pthttpd -ldebian/changelog -Tdebian/thttpd.substvars -Pdebian/.debhelper/thttpd/dbgsym-root -UPre-Depends -URecommends -USuggests -UEnhances -UProvides -UEssential -UConflicts -DPriority=extra -DAuto-Built-Package=debug-symbols -DPackage=thttpd-dbgsym "-DDepends=thttpd (= \${binary:Version})" "-DDescription=Debug symbols for thttpd" -DBuild-Ids=16c41619dbe2621d5592bc2134a67ffe4f585557 -DSection=debug -UMulti-Arch -UReplaces -UBreaks
+       chmod 0644 -- debian/.debhelper/thttpd/dbgsym-root/DEBIAN/control
+       chown 0:0 -- debian/.debhelper/thttpd/dbgsym-root/DEBIAN/control
+       dpkg-gencontrol -pthttpd -ldebian/changelog -Tdebian/thttpd.substvars -Pdebian/thttpd
+       chmod 0644 -- debian/thttpd/DEBIAN/control
+       chown 0:0 -- debian/thttpd/DEBIAN/control
+   dh_md5sums
+       (cd debian/thttpd >/dev/null ; find . -type f  ! -regex './DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum | perl -pe 'if (s@^\\@@) { s/\\\\/\\/g; }' > DEBIAN/md5sums) >/dev/null
+       chmod 0644 -- debian/thttpd/DEBIAN/md5sums
+       chown 0:0 -- debian/thttpd/DEBIAN/md5sums
+       (cd debian/.debhelper/thttpd/dbgsym-root >/dev/null ; find . -type f ! -regex './DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum | perl -pe 'if (s@^\\@@) { s/\\\\/\\/g; }' > DEBIAN/md5sums) >/dev/null
+       chmod 0644 -- debian/.debhelper/thttpd/dbgsym-root/DEBIAN/md5sums
+       chown 0:0 -- debian/.debhelper/thttpd/dbgsym-root/DEBIAN/md5sums
+   dh_builddeb
+       dpkg-deb -z1 -Zxz -Sextreme --build debian/.debhelper/thttpd/dbgsym-root ..
+dpkg-deb: building package 'thttpd-dbgsym' in '../thttpd-dbgsym_2.29-1_amd64.deb'.
+       dpkg-deb --build debian/thttpd ..
+dpkg-deb: building package 'thttpd' in '../thttpd_2.29-1_amd64.deb'.
+ dpkg-genbuildinfo --build=binary
+ dpkg-genchanges --build=binary >../thttpd_2.29-1_amd64.changes
+dpkg-genchanges: info: binary-only upload (no source code included)
+ dpkg-source --after-build thttpd-2.29
+dpkg-buildpackage: info: binary-only upload (no source included)
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..bc3b57f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,174 @@
+# Generated automatically from Makefile.in by configure.
+# Makefile.in for thttpd
+#
+# Copyright © 1995,1998 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Various configurable paths (remember to edit Makefile.in, not Makefile)
+
+# Top level hierarchy.
+prefix = /usr/local
+exec_prefix = ${prefix}
+# Pathname of directory to install the binary.
+BINDIR = ${exec_prefix}/sbin
+# Pathname of directory to install the man page.
+MANDIR = /usr/local/man
+# Pathname of directory to install the CGI programs.
+WEBDIR = $(prefix)/www
+
+# CONFIGURE: The group that the web directory belongs to.  This is so that
+# the makeweb program can be installed set-group-id to that group, and make
+# subdirectories.  If you're not going to use makeweb, ignore this.
+WEBGROUP =     www
+
+# CONFIGURE: Directory for CGI executables.
+CGIBINDIR =    $(WEBDIR)/cgi-bin
+
+# You shouldn't need to edit anything below here.
+
+CC =           gcc
+CCOPT =                -O2
+DEFS =          -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 
+INCLS =                -I.
+CFLAGS =       $(CCOPT) $(DEFS) $(INCLS)
+LDFLAGS =      
+LIBS =         -lcrypt 
+NETLIBS =      
+INSTALL =      /usr/bin/install -c
+
+
+
+.c.o:
+       @rm -f $@
+       $(CC) $(CFLAGS) -c $*.c
+
+SRC =          thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c
+
+OBJ =          $(SRC:.c=.o) 
+
+ALL =          thttpd
+
+GENHDR =       mime_encodings.h mime_types.h
+
+CLEANFILES =   $(ALL) $(OBJ) $(GENSRC) $(GENHDR)
+
+#SUBDIRS =     cgi-src extras
+
+all:           this subdirs
+this:          $(ALL)
+
+thttpd: $(OBJ)
+       @rm -f $@
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS)
+
+mime_encodings.h:      mime_encodings.txt
+       rm -f mime_encodings.h
+       sed < mime_encodings.txt > mime_encodings.h \
+         -e 's/#.*//' -e 's/[  ]*$$//' -e '/^$$/d' \
+         -e 's/[       ][      ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/'
+
+mime_types.h:  mime_types.txt
+       rm -f mime_types.h
+       sed < mime_types.txt > mime_types.h \
+         -e 's/#.*//' -e 's/[  ]*$$//' -e '/^$$/d' \
+         -e 's/[       ][      ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/'
+
+
+subdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) \
+               WEBDIR=$(WEBDIR) \
+               CGIBINDIR=$(CGIBINDIR) \
+               MANDIR=$(MANDIR) \
+               WEBGROUP=$(WEBGROUP) \
+       ) ; done
+
+
+install:       installthis install-man # installsubdirs
+
+installthis:
+       -mkdir -p $(DESTDIR)$(BINDIR)
+       $(INSTALL) -m 555 -o bin -g bin thttpd $(DESTDIR)$(BINDIR)
+
+install-man:
+       -mkdir -p $(DESTDIR)$(MANDIR)/man8
+       $(INSTALL) -m 444 -o bin -g bin thttpd.8 $(DESTDIR)$(MANDIR)/man8
+
+installsubdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) \
+               WEBDIR=$(WEBDIR) \
+               CGIBINDIR=$(CGIBINDIR) \
+               MANDIR=$(MANDIR) \
+               WEBGROUP=$(WEBGROUP) \
+               install \
+       ) ; done
+
+
+clean:         cleansubdirs
+       rm -f $(CLEANFILES)
+
+distclean:     distcleansubdirs
+       rm -f $(CLEANFILES) Makefile config.cache config.log config.status tags
+
+cleansubdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) clean \
+       ) ; done
+
+distcleansubdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) distclean \
+       ) ; done
+
+tags:
+       ctags -wtd *.c *.h
+
+tar:
+       @name=`sed -n -e '/SERVER_SOFTWARE/!d' -e 's,.*thttpd/,thttpd-,' -e 's, .*,,p' version.h` ; \
+         rm -rf $$name ; \
+         mkdir $$name ; \
+         tar cf - `cat FILES` | ( cd $$name ; tar xfBp - ) ; \
+         chmod 644 $$name/Makefile.in $$name/config.h $$name/mime_encodings.txt $$name/mime_types.txt ; \
+         chmod 755 $$name/cgi-bin $$name/cgi-src $$name/contrib $$name/contrib/redhat-rpm $$name/extras $$name/scripts ; \
+         tar cf $$name.tar $$name ; \
+         rm -rf $$name ; \
+         gzip $$name.tar
+
+thttpd.o:      config.h version.h libhttpd.h fdwatch.h mmc.h timers.h match.h
+libhttpd.o:    config.h version.h libhttpd.h mime_encodings.h mime_types.h \
+               mmc.h timers.h match.h tdate_parse.h
+fdwatch.o:     fdwatch.h
+mmc.o:         mmc.h libhttpd.h
+timers.o:      timers.h
+match.o:       match.h
+tdate_parse.o: tdate_parse.h
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..f265388
--- /dev/null
@@ -0,0 +1,173 @@
+# Makefile.in for thttpd
+#
+# Copyright © 1995,1998 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Various configurable paths (remember to edit Makefile.in, not Makefile)
+
+# Top level hierarchy.
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+# Pathname of directory to install the binary.
+BINDIR = @sbindir@
+# Pathname of directory to install the man page.
+MANDIR = @mandir@
+# Pathname of directory to install the CGI programs.
+WEBDIR = $(prefix)/www
+
+# CONFIGURE: The group that the web directory belongs to.  This is so that
+# the makeweb program can be installed set-group-id to that group, and make
+# subdirectories.  If you're not going to use makeweb, ignore this.
+WEBGROUP =     www
+
+# CONFIGURE: Directory for CGI executables.
+CGIBINDIR =    $(WEBDIR)/cgi-bin
+
+# You shouldn't need to edit anything below here.
+
+CC =           @CC@
+CCOPT =                @V_CCOPT@
+DEFS =         @DEFS@
+INCLS =                -I.
+CFLAGS =       $(CCOPT) $(DEFS) $(INCLS)
+LDFLAGS =      @LDFLAGS@
+LIBS =         @LIBS@
+NETLIBS =      @V_NETLIBS@
+INSTALL =      @INSTALL@
+
+@SET_MAKE@
+
+.c.o:
+       @rm -f $@
+       $(CC) $(CFLAGS) -c $*.c
+
+SRC =          thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c
+
+OBJ =          $(SRC:.c=.o) @LIBOBJS@
+
+ALL =          thttpd
+
+GENHDR =       mime_encodings.h mime_types.h
+
+CLEANFILES =   $(ALL) $(OBJ) $(GENSRC) $(GENHDR)
+
+#SUBDIRS =     cgi-src extras
+
+all:           this subdirs
+this:          $(ALL)
+
+thttpd: $(OBJ)
+       @rm -f $@
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS)
+
+mime_encodings.h:      mime_encodings.txt
+       rm -f mime_encodings.h
+       sed < mime_encodings.txt > mime_encodings.h \
+         -e 's/#.*//' -e 's/[  ]*$$//' -e '/^$$/d' \
+         -e 's/[       ][      ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/'
+
+mime_types.h:  mime_types.txt
+       rm -f mime_types.h
+       sed < mime_types.txt > mime_types.h \
+         -e 's/#.*//' -e 's/[  ]*$$//' -e '/^$$/d' \
+         -e 's/[       ][      ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/'
+
+
+subdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) \
+               WEBDIR=$(WEBDIR) \
+               CGIBINDIR=$(CGIBINDIR) \
+               MANDIR=$(MANDIR) \
+               WEBGROUP=$(WEBGROUP) \
+       ) ; done
+
+
+install:       installthis install-man # installsubdirs
+
+installthis:
+       -mkdir -p $(DESTDIR)$(BINDIR)
+       $(INSTALL) -m 555 -o bin -g bin thttpd $(DESTDIR)$(BINDIR)
+
+install-man:
+       -mkdir -p $(DESTDIR)$(MANDIR)/man8
+       $(INSTALL) -m 444 -o bin -g bin thttpd.8 $(DESTDIR)$(MANDIR)/man8
+
+installsubdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) \
+               WEBDIR=$(WEBDIR) \
+               CGIBINDIR=$(CGIBINDIR) \
+               MANDIR=$(MANDIR) \
+               WEBGROUP=$(WEBGROUP) \
+               install \
+       ) ; done
+
+
+clean:         cleansubdirs
+       rm -f $(CLEANFILES)
+
+distclean:     distcleansubdirs
+       rm -f $(CLEANFILES) Makefile config.cache config.log config.status tags
+
+cleansubdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) clean \
+       ) ; done
+
+distcleansubdirs:
+       for i in $(SUBDIRS) ; do ( \
+           cd $$i ; \
+           pwd ; \
+           $(MAKE) $(MFLAGS) distclean \
+       ) ; done
+
+tags:
+       ctags -wtd *.c *.h
+
+tar:
+       @name=`sed -n -e '/SERVER_SOFTWARE/!d' -e 's,.*thttpd/,thttpd-,' -e 's, .*,,p' version.h` ; \
+         rm -rf $$name ; \
+         mkdir $$name ; \
+         tar cf - `cat FILES` | ( cd $$name ; tar xfBp - ) ; \
+         chmod 644 $$name/Makefile.in $$name/config.h $$name/mime_encodings.txt $$name/mime_types.txt ; \
+         chmod 755 $$name/cgi-bin $$name/cgi-src $$name/contrib $$name/contrib/redhat-rpm $$name/extras $$name/scripts ; \
+         tar cf $$name.tar $$name ; \
+         rm -rf $$name ; \
+         gzip $$name.tar
+
+thttpd.o:      config.h version.h libhttpd.h fdwatch.h mmc.h timers.h match.h
+libhttpd.o:    config.h version.h libhttpd.h mime_encodings.h mime_types.h \
+               mmc.h timers.h match.h tdate_parse.h
+fdwatch.o:     fdwatch.h
+mmc.o:         mmc.h libhttpd.h
+timers.o:      timers.h
+match.o:       match.h
+tdate_parse.o: tdate_parse.h
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..a63f49e
--- /dev/null
+++ b/README
@@ -0,0 +1,31 @@
+             thttpd - tiny/turbo/throttling HTTP server
+                    version 2.29 of 23May2018
+
+thttpd is a simple, small, portable, fast, and secure HTTP server.
+
+Simple: It handles only the minimum necessary to implement HTTP/1.1.
+
+Small: See the size comparison chart at
+http://www.acme.com/software/thttpd/notes.html#sizes.  It also has a
+very small run-time size, since it does not fork and is very careful about
+memory allocation.
+
+Portable: It compiles cleanly on FreeBSD 2.x/3.x, SunOS 4.1.x, Solaris 2.x,
+BSD/OS 2.x, Linux 1.2.x, OSF/1 (on a 64-bit Alpha), and no doubt many others.
+
+Fast: In typical use it's about as fast as the best full-featured servers
+(Apache, NCSA, Netscape).  Under extreme load it's much faster.
+
+Secure: It goes to great lengths to protect the web server machine
+against attacks and breakins from other sites.
+
+It also has one extremely useful feature (URL-traffic-based throttling) that
+no other server currently has.
+
+See the manual entry for more details.  See the INSTALL file for
+configuration and installation instructions.  Check the web page
+(http://www.acme.com/software/thttpd/) for updates, or add yourself to
+the mailing list by sending a "subscribe" to thttpd-announce-request@mail.acme.com.
+
+Comments to:
+    Jef Poskanzer  jef@mail.acme.com  http://www.acme.com/jef/
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..ab5dd21
--- /dev/null
+++ b/TODO
@@ -0,0 +1,80 @@
+- - - - - - - - - - high priority - - - - - - - - - -
+
+IPv6 not working right.
+
+Problem with ACME News downloads.  PATH_INFO interferes with the authorization.
+
+Why is the client's IP address showing up in paths?
+
+Fetches with numeric IP addresses and no Host: header are screwing up the
+vhost code?
+143.90.193.229 - - [06/Apr/2000:09:21:34 -0700] "GET /209.133.38.22/software/thttpd/ HTTP/1.0" 200 12093 "http://www.dbphotography.demon.co.uk/index.html" "Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)"
+143.90.193.229 - - [06/Apr/2000:09:21:37 -0700] "GET /143.90.193.229/software/thttpd/anvil_thttpd.gif HTTP/1.0" 403 - "http://www.acme.com/software/thttpd/" "Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)"
+
+Have directory indexing skip files that start with dot?  Except ..?
+In libhttpd.c:
++               if (*(de->d_name) == '.' && *(de->d_name+1) != '.')
++                   continue;
+                namlen = NAMLEN(de);
+
+Add comment on INDEX_NAMES that it should be simple filenames only.
+
+The error page generated for non-local referers should include the
+original URL as an active link.
+
+Make open in mmc.c use O_NONBLOCK flag, to prevent DOS attack via
+a named pipe?
+
+- - - - - - - - - - later - - - - - - - - - -
+
+Document how symlinks interact with .htpasswd - authorization is checked
+on the result of the symlink, and not the origin.
+
+SIGHUP log re-opening doesn't work if you started as root.
+
+Change redirect to put the Refresh command in the HTTP headers, instead of
+a META tag.
+
+Add TCP_NODELAY, but after CGIs get spawned.
+
+Add stat cache?  1 minute expiry?
+
+Ifdef the un-close-on-exec CGI thing for Linux only.
+
+Add keep-alives, via a new state in thttpd.c.
+
+- - - - - - - - - - someday - - - - - - - - - -
+
+The special world-permissions checking is probably bogus.  For one
+thing, it doesn't handle restrictive permissions on parent directories
+properly.  It should probably just go away.
+
+redirect should interpret a path with a trailing / as /index.html
+
+ssi should change $cwd to the source document's location.
+
+Allow .throttle files in individual directories.
+
+Log-digesting scripts.
+
+Config web page.
+    Common errors:
+       Not realizing that -c overrides CGI_PATTERN instead of augmenting it.
+       Using a directory name for the -c pattern.
+
+- - - - - - - - - - 3.x - - - - - - - - - -
+
+Tasklets re-write.
+
+- - - - - - - - - - general - - - - - - - - - -
+
+Release process:
+  - update version number in version.h README INSTALL and
+    contrib/redhat-rpm/thttpd.spec
+  - do a tdiff and update the local installation
+  - do an rcstreeinfo, and check in all files
+  - make tar
+  - mv it to ..
+  - update version number in ../thttpd.html
+  - update ~acmeweb/updates.html
+  - mail announcement to thttpd-announce
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..ff35a25
--- /dev/null
@@ -0,0 +1,188 @@
+dnl
+dnl Improved version of AC_CHECK_LIB
+dnl
+dnl Thanks to John Hawkinson (jhawk@mit.edu)
+dnl
+dnl usage:
+dnl
+dnl    AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [,
+dnl        ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]])
+dnl
+dnl results:
+dnl
+dnl    LIBS
+dnl
+
+define(AC_LBL_CHECK_LIB,
+[AC_MSG_CHECKING([for $2 in -l$1])
+dnl Use a cache variable name containing both the library and function name,
+dnl because the test really is for library $1 defining function $2, not
+dnl just for library $1.  Separate tests with the same $1 and different $2's
+dnl may have different results.
+ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'`
+AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var,
+[ac_save_LIBS="$LIBS"
+LIBS="-l$1 $5 $LIBS"
+AC_TRY_LINK(dnl
+ifelse([$2], [main], , dnl Avoid conflicting decl of main.
+[/* Override any gcc2 internal prototype to avoid an error.  */
+]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus
+extern "C"
+#endif
+])dnl
+[/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $2();
+]),
+           [$2()],
+           eval "ac_cv_lbl_lib_$ac_lib_var=yes",
+           eval "ac_cv_lbl_lib_$ac_lib_var=no")
+LIBS="$ac_save_LIBS"
+])dnl
+if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  ifelse([$3], ,
+[changequote(, )dnl
+  ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+changequote([, ])dnl
+  AC_DEFINE_UNQUOTED($ac_tr_lib)
+  LIBS="-l$1 $LIBS"
+], [$3])
+else
+  AC_MSG_RESULT(no)
+ifelse([$4], , , [$4
+])dnl
+fi
+])
+
+dnl
+dnl AC_LBL_LIBRARY_NET
+dnl
+dnl This test is for network applications that need socket() and
+dnl gethostbyname() -ish functions.  Under Solaris, those applications
+dnl need to link with "-lsocket -lnsl".  Under IRIX, they need to link
+dnl with "-lnsl" but should *not* link with "-lsocket" because
+dnl libsocket.a breaks a number of things (for instance:
+dnl gethostbyname() under IRIX 5.2, and snoop sockets under most
+dnl versions of IRIX).
+dnl
+dnl Unfortunately, many application developers are not aware of this,
+dnl and mistakenly write tests that cause -lsocket to be used under
+dnl IRIX.  It is also easy to write tests that cause -lnsl to be used
+dnl under operating systems where neither are necessary (or useful),
+dnl such as SunOS 4.1.4, which uses -lnsl for TLI.
+dnl
+dnl This test exists so that every application developer does not test
+dnl this in a different, and subtly broken fashion.
+
+dnl It has been argued that this test should be broken up into two
+dnl seperate tests, one for the resolver libraries, and one for the
+dnl libraries necessary for using Sockets API. Unfortunately, the two
+dnl are carefully intertwined and allowing the autoconf user to use
+dnl them independantly potentially results in unfortunate ordering
+dnl dependancies -- as such, such component macros would have to
+dnl carefully use indirection and be aware if the other components were
+dnl executed. Since other autoconf macros do not go to this trouble,
+dnl and almost no applications use sockets without the resolver, this
+dnl complexity has not been implemented.
+dnl
+dnl The check for libresolv is in case you are attempting to link
+dnl statically and happen to have a libresolv.a lying around (and no
+dnl libnsl.a).
+dnl
+AC_DEFUN(AC_LBL_LIBRARY_NET, [
+    # Most operating systems have gethostbyname() in the default searched
+    # libraries (i.e. libc):
+    AC_CHECK_FUNC(gethostbyname, ,
+       # Some OSes (eg. Solaris) place it in libnsl:
+       AC_LBL_CHECK_LIB(nsl, gethostbyname, , 
+           # Some strange OSes (SINIX) have it in libsocket:
+           AC_LBL_CHECK_LIB(socket, gethostbyname, ,
+               # Unfortunately libsocket sometimes depends on libnsl.
+               # AC_CHECK_LIB's API is essentially broken so the
+               # following ugliness is necessary:
+               AC_LBL_CHECK_LIB(socket, gethostbyname,
+                   LIBS="-lsocket -lnsl $LIBS",
+                   AC_CHECK_LIB(resolv, gethostbyname),
+                   -lnsl))))
+    AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+       AC_LBL_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", ,
+           -lnsl)))
+    # DLPI needs putmsg under HPUX so test for -lstr while we're at it
+    AC_CHECK_LIB(str, putmsg)
+    ])
+
+dnl
+dnl Checks to see if struct tm has the BSD tm_gmtoff member
+dnl
+dnl usage:
+dnl
+dnl    AC_ACME_TM_GMTOFF
+dnl
+dnl results:
+dnl
+dnl    HAVE_TM_GMTOFF (defined)
+dnl
+AC_DEFUN(AC_ACME_TM_GMTOFF,
+    [AC_MSG_CHECKING(if struct tm has tm_gmtoff member)
+    AC_CACHE_VAL(ac_cv_acme_tm_has_tm_gmtoff,
+       AC_TRY_COMPILE([
+#      include <sys/types.h>
+#      include <time.h>],
+       [u_int i = sizeof(((struct tm *)0)->tm_gmtoff)],
+       ac_cv_acme_tm_has_tm_gmtoff=yes,
+       ac_cv_acme_tm_has_tm_gmtoff=no))
+    AC_MSG_RESULT($ac_cv_acme_tm_has_tm_gmtoff)
+    if test $ac_cv_acme_tm_has_tm_gmtoff = yes ; then
+           AC_DEFINE(HAVE_TM_GMTOFF)
+    fi])
+
+dnl
+dnl Checks to see if int64_t exists
+dnl
+dnl usage:
+dnl
+dnl    AC_ACME_INT64T
+dnl
+dnl results:
+dnl
+dnl    HAVE_INT64T (defined)
+dnl
+AC_DEFUN(AC_ACME_INT64T,
+    [AC_MSG_CHECKING(if int64_t exists)
+    AC_CACHE_VAL(ac_cv_acme_int64_t,
+       AC_TRY_COMPILE([
+#      include <sys/types.h>],
+       [int64_t i64],
+       ac_cv_acme_int64_t=yes,
+       ac_cv_acme_int64_t=no))
+    AC_MSG_RESULT($ac_cv_acme_int64_t)
+    if test $ac_cv_acme_int64_t = yes ; then
+           AC_DEFINE(HAVE_INT64T)
+    fi])
+
+dnl
+dnl Checks to see if socklen_t exists
+dnl
+dnl usage:
+dnl
+dnl    AC_ACME_SOCKLENT
+dnl
+dnl results:
+dnl
+dnl    HAVE_SOCKLENT (defined)
+dnl
+AC_DEFUN(AC_ACME_SOCKLENT,
+    [AC_MSG_CHECKING(if socklen_t exists)
+    AC_CACHE_VAL(ac_cv_acme_socklen_t,
+       AC_TRY_COMPILE([
+#      include <sys/types.h>
+#      include <sys/socket.h>],
+       [socklen_t slen],
+       ac_cv_acme_socklen_t=yes,
+       ac_cv_acme_socklen_t=no))
+    AC_MSG_RESULT($ac_cv_acme_socklen_t)
+    if test $ac_cv_acme_socklen_t = yes ; then
+           AC_DEFINE(HAVE_SOCKLENT)
+    fi])
diff --git a/cgi-bin/printenv b/cgi-bin/printenv
new file mode 100755 (executable)
index 0000000..cb5df7e
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+date=`date -u '+%a, %d %b %Y %H:%M:%S %Z'`
+
+cat << EOF
+Content-type: text/plain
+Expires: $date
+
+CGI printenv
+
+EOF
+
+echo 'Date:'
+date
+echo
+echo 'Id:'
+id
+echo
+echo 'Env:'
+printenv
+echo
+if [ "$CONTENT_LENGTH" != "" ] ; then
+    if [ "$CONTENT_LENGTH" -ne 0 ] ; then
+       echo 'Input:'
+       echo
+       dd bs=1 count=$CONTENT_LENGTH
+       echo
+    fi
+fi
diff --git a/cgi-src/Makefile b/cgi-src/Makefile
new file mode 100644 (file)
index 0000000..4857282
--- /dev/null
@@ -0,0 +1,87 @@
+# Generated automatically from Makefile.in by configure.
+# Makefile for cgi-src
+#
+# Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+prefix =       /usr/local
+exec_prefix =  ${prefix}
+WEBDIR =       $(prefix)/www
+CGIBINDIR =    $(WEBDIR)/cgi-bin
+MANDIR =       /usr/local/man
+
+CC =           gcc
+CCOPT =                -O2
+DEFS =          -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 
+INCLS =                -I..
+CFLAGS =       $(CCOPT) $(DEFS) $(INCLS)
+LDFLAGS =       
+LIBS =         -lcrypt 
+NETLIBS =      
+INSTALL =      /usr/bin/install -c
+
+CLEANFILES =   *.o redirect ssi phf
+
+
+
+.c.o:
+       @rm -f $@
+       $(CC) $(CFLAGS) -c $*.c
+
+all:           redirect ssi phf
+
+redirect:      redirect.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) redirect.o $(LIBS) -o redirect
+
+ssi:           ssi.o ../match.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) ssi.o ../match.o $(LIBS) -o ssi
+
+ssi.o:         ../match.h
+
+phf:           phf.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) phf.o $(LIBS) -o phf
+
+strerror.o:
+       @rm -f strerror.o
+       @ln -s ../strerror.o
+       cd .. ; $(MAKE) $(MFLAGS) strerror.o
+
+install:       all
+       -mkdir -p $(CGIBINDIR)
+       rm -f $(CGIBINDIR)/redirect
+       cp redirect $(CGIBINDIR)/redirect
+       rm -f $(MANDIR)/man8/redirect.8
+       cp redirect.8 $(MANDIR)/man8/redirect.8
+       rm -f $(CGIBINDIR)/ssi
+       cp ssi $(CGIBINDIR)/ssi
+       rm -f $(MANDIR)/man8/ssi.8
+       cp ssi.8 $(MANDIR)/man8/ssi.8
+       rm -f $(CGIBINDIR)/phf
+       cp phf $(CGIBINDIR)/phf
+
+clean:
+       rm -f $(CLEANFILES)
+
+distclean:
+       rm -f $(CLEANFILES) Makefile
diff --git a/cgi-src/Makefile.in b/cgi-src/Makefile.in
new file mode 100644 (file)
index 0000000..6e4e9ba
--- /dev/null
@@ -0,0 +1,86 @@
+# Makefile for cgi-src
+#
+# Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+prefix =       @prefix@
+exec_prefix =  @exec_prefix@
+WEBDIR =       $(prefix)/www
+CGIBINDIR =    $(WEBDIR)/cgi-bin
+MANDIR =       @mandir@
+
+CC =           @CC@
+CCOPT =                @V_CCOPT@
+DEFS =         @DEFS@
+INCLS =                -I..
+CFLAGS =       $(CCOPT) $(DEFS) $(INCLS)
+LDFLAGS =      @LDFLAGS@ @V_STATICFLAG@
+LIBS =         @LIBS@
+NETLIBS =      @V_NETLIBS@
+INSTALL =      @INSTALL@
+
+CLEANFILES =   *.o redirect ssi phf
+
+@SET_MAKE@
+
+.c.o:
+       @rm -f $@
+       $(CC) $(CFLAGS) -c $*.c
+
+all:           redirect ssi phf
+
+redirect:      redirect.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) redirect.o $(LIBS) -o redirect
+
+ssi:           ssi.o ../match.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) ssi.o ../match.o $(LIBS) -o ssi
+
+ssi.o:         ../match.h
+
+phf:           phf.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) phf.o $(LIBS) -o phf
+
+strerror.o:
+       @rm -f strerror.o
+       @ln -s ../strerror.o
+       cd .. ; $(MAKE) $(MFLAGS) strerror.o
+
+install:       all
+       -mkdir -p $(CGIBINDIR)
+       rm -f $(CGIBINDIR)/redirect
+       cp redirect $(CGIBINDIR)/redirect
+       rm -f $(MANDIR)/man8/redirect.8
+       cp redirect.8 $(MANDIR)/man8/redirect.8
+       rm -f $(CGIBINDIR)/ssi
+       cp ssi $(CGIBINDIR)/ssi
+       rm -f $(MANDIR)/man8/ssi.8
+       cp ssi.8 $(MANDIR)/man8/ssi.8
+       rm -f $(CGIBINDIR)/phf
+       cp phf $(CGIBINDIR)/phf
+
+clean:
+       rm -f $(CLEANFILES)
+
+distclean:
+       rm -f $(CLEANFILES) Makefile
diff --git a/cgi-src/phf.c b/cgi-src/phf.c
new file mode 100644 (file)
index 0000000..6d06b65
--- /dev/null
@@ -0,0 +1,69 @@
+/* phf - cracker trap
+**
+** Old distributions of the NCSA and Apache web servers included a
+** version of the phf program that had a bug.  The program could
+** easily be made to run arbitrary shell commands.  There is no real
+** legitimate use for phf, so any attempts to run it must be considered
+** to be attacks.  Accordingly, this version of phf logs the attack
+** and then returns a page indicating that phf doesn't exist.
+**
+**
+** Copyright © 1996 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "config.h"
+
+static char* argv0;
+
+int
+main( int argc, char* argv[] )
+    {
+    char* cp;
+
+    argv0 = argv[0];
+    cp = strrchr( argv0, '/' );
+    if ( cp != (char*) 0 )
+       ++cp;
+    else
+       cp = argv0;
+    openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY );
+    syslog( LOG_CRIT, "phf CGI probe from %s", getenv( "REMOTE_ADDR" ) );
+    (void) printf( "\
+Content-type: text/html\n\
+Status: 404/html\n\
+\n\
+<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n\
+<BODY><H2>404 Not Found</H2>\n\
+The requested object does not exist on this server.\n\
+The link you followed is either outdated, inaccurate,\n\
+or the server has been instructed not to let you have it.\n\
+</BODY></HTML>\n" );
+    exit( 0 );
+    }
diff --git a/cgi-src/redirect.8 b/cgi-src/redirect.8
new file mode 100644 (file)
index 0000000..69a96e1
--- /dev/null
@@ -0,0 +1,79 @@
+.TH redirect 8 "23 September 1995"
+.SH NAME
+redirect - simple redirection CGI program
+.SH SYNOPSIS
+.B redirect
+.SH DESCRIPTION
+.PP
+Three steps to set up a redirection:
+.PP
+1. Make sure your web server is set up to allow CGI programs.
+.PP
+2. Make a symbolic link from the file or directory you want to redirect,
+pointing at this program in the CGI bin directory.
+.PP
+3. Add an entry to the file ".redirects" in the directory where your
+http server runs CGI programs.  For most servers, this is the
+directory where the given CGI program lives.  The format of the
+file is a bunch of lines with a filename, whitespace, and the new
+URL.  For example:
+.nf
+  /test/oldfile.html    http://www.acme.com/test/newfile.html
+.fi
+The easiest way to figure out precisely what filename to put into .redirects
+is to set up the symlink and then click on it.
+You'll get back a "404 Not Found" page which includes the filename
+as received by the redirect program, and that's what you want to use.
+.PP
+You can also add a wildcard specification to redirect whole groups of files.
+For example:
+.nf
+  /wildtest/*          http://www.acme.com/test-
+.fi
+will cause an access to the /wildtest/somefile.html to be redirected to
+http://www.acme.com/test-somefile.html. (Note that the asterisk need not
+be preceded by a slash.)
+.PP
+Note: this is designed for thttpd (http://www.acme.com/software/thttpd/)
+and using it with other web servers may require some hacking.  A possible
+gotcha is with the symbolic link from the old file pointing at this
+script - servers other than thttpd may not allow that link to be run
+as a CGI program, because they don't check the link to see that it
+points into the allowed CGI directory.
+.SH "SEE ALSO"
+thttpd(8)
+.SH "BUGS / DEFICIENCIES"
+.PP
+It would be really cool to have this program look for
+the .redirects file in the same directory as the file being redirected,
+instead of in the binaries directory.  Unfortunately, this appears
+to be impossible with the information CGI gives, plus the non-standardized
+but widespread practice of running CGI programs in the directory where
+the binary lives.  Perhaps CGI 1.2 will address this.
+.PP
+The wildcard mechanism is very primitive.
+In particular, any characters that follow the asterisk are blithely
+ignored.
+.SH AUTHOR
+Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
diff --git a/cgi-src/redirect.c b/cgi-src/redirect.c
new file mode 100644 (file)
index 0000000..d1caac0
--- /dev/null
@@ -0,0 +1,215 @@
+/* redirect - simple redirection CGI program
+**
+** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+/* Three steps to set up a redirection:
+**  1. Make sure your web server is set up to allow CGI programs.
+**  2. Make a symbolic link from the file you want to redirect,
+**     pointing at this program in the CGI bin directory.
+**  3. Add an entry to the file ".redirects" in the directory where your
+**     http server runs CGI programs.  For most servers, this is the
+**     directory where the given CGI program lives.  The format of the
+**     file is a bunch of lines with a filename, whitespace, and the new
+**     URL.  For example:
+
+/test/oldfile.html    http://www.acme.com/test/newfile.html
+
+**     The easiest way to figure out precisely what filename to put into
+**     .redirects is to set up the symlink and then click on it.  You'll get
+**     back a "404 Not Found" page which includes the filename as received by
+**     the redirect program, and that's what you want to use.
+**
+** Note: this is designed for thttpd (http://www.acme.com/software/thttpd/)
+** and using it with other web servers may require some hacking.  A possible
+** gotcha is with the symbolic link from the old file pointing at this
+** script - servers other than thttpd may not allow that link to be run
+** as a CGI program, because they don't check the link to see that it
+** points into the allowed CGI directory.
+**
+** Note two: It would be really cool to have this program look for
+** the .redirects file in the same directory as the file being redirected,
+** instead of in the binaries directory.  Unfortunately, this appears
+** to be impossible with the information CGI gives, plus the non-standardized
+** but widespread practice of running CGI programs in the directory where
+** the binary lives.  Perhaps CGI 1.2 will address this.
+*/
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+
+static char* argv0;
+
+
+static void
+internal_error( char* reason )
+    {
+    char* title = "500 Internal Error";
+
+    (void) printf( "\
+Status: %s\n\
+Content-type: text/html\n\
+\n\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+Something unusual went wrong during a redirection request:\n\
+<BLOCKQUOTE>\n\
+%s\n\
+</BLOCKQUOTE>\n\
+</BODY></HTML>\n", title, title, title, reason );
+    }
+
+
+static void
+not_found( char* script_name )
+    {
+    char* title = "404 Not Found";
+
+    (void) printf( "\
+Status: %s\n\
+Content-type: text/html\n\
+\n\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+The requested filename, %s, is set up to be redirected to another URL;\n\
+however, the new URL has not yet been specified.\n\
+</BODY></HTML>\n", title, title, title, script_name );
+    }
+
+
+static void
+moved( char* script_name, char* url )
+    {
+    char* title = "Moved";
+
+    (void) printf( "\
+Location: %s\n\
+Content-type: text/html\n\
+\n\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+The requested filename, %s, has moved to a new URL:\n\
+<A HREF=\"%s\">%s</A>.\n\
+</BODY></HTML>\n", url, title, title, script_name, url, url );
+    }
+       
+
+int
+main( int argc, char** argv )
+    {
+    char* script_name;
+    char* path_info;
+    char* cp;
+    FILE* fp;
+    char *star;
+    char buf[5000], file[5000], url[5000];
+
+    argv0 = argv[0];
+
+    /* Get the name that we were run as, which is the filename being
+    ** redirected.
+    */
+    script_name = getenv( "SCRIPT_NAME" );
+    if ( script_name == (char*) 0 )
+       {
+       internal_error( "Couldn't get SCRIPT_NAME environment variable." );
+       exit( 1 );
+       }
+
+    /* Append the PATH_INFO, if any.  This allows redirection of whole
+    ** directories.
+    */
+    path_info = getenv( "PATH_INFO" );
+    if ( path_info != (char*) 0 )
+       {
+       cp = (char*) malloc( strlen( script_name ) + strlen( path_info ) + 1 );
+       if ( cp == (char*) 0 )
+           {
+           internal_error( "Out of memory." );
+           exit( 1 );
+           }
+       (void) sprintf( cp, "%s%s", script_name, path_info );
+       script_name = cp;
+       }
+
+    /* Open the redirects file. */
+    fp = fopen( ".redirects", "r" );
+    if ( fp == (FILE*) 0 )
+       {
+       internal_error( "Couldn't open .redirects file." );
+       exit( 1 );
+       }
+
+    /* Search the file for a matching entry. */
+    while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 )
+       {
+       /* Remove comments. */
+       cp = strchr( buf, '#' );
+       if ( cp != (char*) 0 )
+           *cp = '\0';
+       /* Skip leading whitespace. */
+       cp = buf;
+       cp += strspn( cp, " \t" );
+       /* Check for blank line. */
+       if ( *cp != '\0' )
+           {
+           /* Parse line. */
+           if ( sscanf( cp, "%[^ \t\n] %[^ \t\n]", file, url ) == 2 )
+               {
+               /* Check for wildcard match. */
+               star = strchr( file, '*' );
+               if ( star != (char*) 0 )
+                   {
+                   /* Check for leading match. */
+                   if ( strncmp( file, script_name, star - file ) == 0 )
+                       {
+                       /* Got it; put together the full name. */
+                       strcat( url, script_name + ( star - file ) );
+                       /* XXX Whack the script_name, too? */
+                       moved( script_name, url );
+                       exit( 0 );
+                       }
+                   }
+               /* Check for exact match. */
+               if ( strcmp( file, script_name ) == 0 )
+                   {
+                   /* Got it. */
+                   moved( script_name, url );
+                   exit( 0 );
+                   }
+               }
+           }
+       }
+
+    /* No match found. */
+    not_found( script_name );
+    exit( 1 );
+    }
diff --git a/cgi-src/ssi.8 b/cgi-src/ssi.8
new file mode 100644 (file)
index 0000000..01c2045
--- /dev/null
@@ -0,0 +1,142 @@
+.TH ssi 8 "18 October 1995"
+.SH NAME
+ssi - server-side-includes CGI program
+.SH SYNOPSIS
+.B ssi
+.SH DESCRIPTION
+.PP
+This is an external CGI program that gives you the same functionality
+as the built-in server-side-includes feature in some HTTP daemons.
+It is written for use with thttpd(8), but should be easy to adapt
+to other systems.
+.PP
+To use this program, first make sure it is installed in your server's
+CGI area, and that CGI is enabled.
+Then set up your URLs with the path to the document you want parsed
+as the "pathinfo".
+That's the part of the URL that comes after the CGI program name.
+For example, if the URL to this program is:
+.nf
+  http://www.acme.com/cgi-bin/ssi
+.fi
+and the url for your document is:
+.nf
+  http://www.acme.com/users/wecoyote/doc.html
+.fi
+then the compound URL that gives you the document filtered through the
+program would be:
+.nf
+  http://www.acme.com/cgi-bin/ssi/users/wecoyote/doc.html
+.fi
+.PP
+The format description below is adapted from
+http://hoohoo.ncsa.uiuc.edu/docs/tutorials/includes.html
+.SH "INCLUDE FORMAT"
+.PP
+All directives are formatted as SGML comments within the document.
+This is in case the document should ever find itself in the client's
+hands unparsed.
+Each directive has the following format:
+.nf
+  <!--#command tag1="value1" tag2="value2" -->
+.fi
+Each command takes different arguments, most only accept one tag at a time.
+Here is a breakdown of the commands and their associated tags:
+.IP * 4
+.BR config :
+The config directive controls various aspects of the file parsing.
+There are two valid tags:
+.IP o 8
+.BR timefmt :
+gives the server a new format to use when providing dates.
+This is a string compatible with the strftime library call.
+.IP o 8
+.BR sizefmt :
+determines the formatting to be used when displaying the
+size of a file.
+Valid choices are bytes, for a formatted byte count
+(formatted as 1,234,567), or abbrev for an abbreviated version
+displaying the number of kilobytes or megabytes the file occupies.
+.IP * 4
+.BR include :
+Inserts the text of another document into the parsed document.
+The inserted file is parsed recursively, so it can contain
+server-side-include directives too.
+This command accepts two tags:
+.IP o 8
+.BR virtual :
+Gives a virtual path to a document on the server.
+.IP o 8
+.BR file :
+Gives a pathname relative to the current directory. ../ cannot
+be used in this pathname, nor can absolute paths be used.
+.IP * 4
+.BR echo :
+Prints the value of one of the include variables (defined below).
+Any dates are printed subject to the currently configured timefmt.
+The only valid tag to this command is var, whose value is the name of the
+variable you wish to echo.
+.IP * 4
+.BR fsize :
+prints the size of the specified file,
+subject to the sizefmt parameter to the config command.
+Valid tags are the same as with the include command.
+.IP * 4
+.BR flastmod :
+prints the last modification date of the specified file, subject
+to the formatting preference given by the timefmt parameter to config.
+Valid tags are the same as with the include command.
+.SH VARIABLES
+.PP
+A number of variables are made available to parsed documents.
+In addition to
+the CGI variable set, the following variables are made available:
+.IP * 4
+.BR DOCUMENT_NAME :
+The current filename.
+.IP * 4
+.BR DOCUMENT_URI :
+The virtual path to this document (such as /~robm/foo.shtml).
+.IP * 4
+.BR QUERY_STRING_UNESCAPED :
+The unescaped version of any search query the client sent.
+.IP * 4
+.BR DATE_LOCAL :
+The current date, local time zone.
+Subject to the timefmt parameter to the config command.
+.IP * 4
+.BR DATE_GMT :
+Same as DATE_LOCAL but in Greenwich mean time.
+.IP * 4
+.BR LAST_MODIFIED :
+The last modification date of the current document.
+Subject to timefmt like the others.
+.SH "BUGS / DEFICIENCIES"
+.PP
+Does not implement the "exec" directive.
+Actually, I consider this neither a bug nor a deficiency, but some may.
+.SH "SEE ALSO"
+thttpd(8), strftime(3)
+.SH AUTHOR
+Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
diff --git a/cgi-src/ssi.c b/cgi-src/ssi.c
new file mode 100644 (file)
index 0000000..1b0950d
--- /dev/null
@@ -0,0 +1,763 @@
+/* ssi - server-side-includes CGI program
+**
+** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "match.h"
+
+
+#define ST_GROUND 0
+#define ST_LESSTHAN 1
+#define ST_BANG 2
+#define ST_MINUS1 3
+#define ST_MINUS2 4
+
+
+static void read_file( char* vfilename, char* filename, FILE* fp );
+
+
+static char* argv0;
+static char* url;
+
+static char timefmt[100];
+static int sizefmt;
+#define SF_BYTES 0
+#define SF_ABBREV 1
+static struct stat sb;
+
+
+static void
+internal_error( char* reason )
+    {
+    char* title = "500 Internal Error";
+
+    (void) printf( "\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+Something unusual went wrong during a server-side-includes request:\n\
+<BLOCKQUOTE>\n\
+%s\n\
+</BLOCKQUOTE>\n\
+</BODY></HTML>\n", title, title, reason );
+    }
+
+
+static void
+not_found( char* filename )
+    {
+    char* title = "404 Not Found";
+
+    (void) printf( "\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+The requested server-side-includes filename, %s,\n\
+does not seem to exist.\n\
+</BODY></HTML>\n", title, title, filename );
+    }
+
+
+static void
+not_found2( char* directive, char* tag, char* filename2 )
+    {
+    char* title = "Not Found";
+
+    (void) printf( "\
+<HR><H2>%s</H2>\n\
+The filename requested in a %s %s directive, %s,\n\
+does not seem to exist.\n\
+<HR>\n", title, directive, tag, filename2 );
+    }
+
+
+static void
+not_permitted( char* directive, char* tag, char* val )
+    {
+    char* title = "Not Permitted";
+
+    (void) printf( "\
+<HR><H2>%s</H2>\n\
+The filename requested in the %s %s=%s directive\n\
+may not be fetched.\n\
+<HR>\n", title, directive, tag, val );
+    }
+
+
+static void
+unknown_directive( char* filename, char* directive )
+    {
+    char* title = "Unknown Directive";
+
+    (void) printf( "\
+<HR><H2>%s</H2>\n\
+The requested server-side-includes filename, %s,\n\
+tried to use an unknown directive, %s.\n\
+<HR>\n", title, filename, directive );
+    }
+
+
+static void
+unknown_tag( char* filename, char* directive, char* tag )
+    {
+    char* title = "Unknown Tag";
+
+    (void) printf( "\
+<HR><H2>%s</H2>\n\
+The requested server-side-includes filename, %s,\n\
+tried to use the directive %s with an unknown tag, %s.\n\
+<HR>\n", title, filename, directive, tag );
+    }
+
+
+static void
+unknown_value( char* filename, char* directive, char* tag, char* val )
+    {
+    char* title = "Unknown Value";
+
+    (void) printf( "\
+<HR><H2>%s</H2>\n\
+The requested server-side-includes filename, %s,\n\
+tried to use the directive %s %s with an unknown value, %s.\n\
+<HR>\n", title, filename, directive, tag, val );
+    }
+
+
+static int
+get_filename( char* vfilename, char* filename, char* directive, char* tag, char* val, char* fn, int fnsize )
+    {
+    int vl, fl;
+    char* cp;
+
+    /* Used for the various commands that accept a file name.
+    ** These commands accept two tags:
+    **   virtual
+    **     Gives a virtual path to a document on the server.
+    **   file
+    **     Gives a pathname relative to the current directory. ../ cannot
+    **     be used in this pathname, nor can absolute paths be used.
+    */
+    vl = strlen( vfilename );
+    fl = strlen( filename );
+    if ( strcmp( tag, "virtual" ) == 0 )
+       {
+       if ( strstr( val, "../" ) != (char*) 0 )
+           {
+           not_permitted( directive, tag, val );
+           return -1;
+           }
+       /* Figure out root using difference between vfilename and filename. */
+       if ( vl > fl ||
+            strcmp( vfilename, &filename[fl - vl] ) != 0 )
+           return -1;
+       if ( fl - vl + strlen( val ) >= fnsize )
+           return -1;
+       (void) strncpy( fn, filename, fl - vl );
+       (void) strcpy( &fn[fl - vl], val );
+       }
+    else if ( strcmp( tag, "file" ) == 0 )
+       {
+       if ( val[0] == '/' || strstr( val, "../" ) != (char*) 0 )
+           {
+           not_permitted( directive, tag, val );
+           return -1;
+           }
+       if ( fl + 1 + strlen( val ) >= fnsize )
+           return -1;
+       (void) strcpy( fn, filename );
+       cp = strrchr( fn, '/' );
+       if ( cp == (char*) 0 )
+           {
+           cp = &fn[strlen( fn )];
+           *cp = '/';
+           }
+       (void) strcpy( ++cp, val );
+       }
+    else
+       {
+       unknown_tag( filename, directive, tag );
+       return -1;
+       }
+    return 0;
+    }
+
+
+static int
+check_filename( char* filename )
+    {
+    static int inited = 0;
+    static char* cgi_pattern;
+    int fnl;
+    char* cp;
+    char* dirname;
+    char* authname;
+    struct stat sb2;
+    int r;
+
+    if ( ! inited )
+       {
+       /* Get the cgi pattern. */
+       cgi_pattern = getenv( "CGI_PATTERN" );
+#ifdef CGI_PATTERN
+       if ( cgi_pattern == (char*) 0 )
+           cgi_pattern = CGI_PATTERN;
+#endif /* CGI_PATTERN */
+       inited = 1;
+       }
+
+    /* ../ is not permitted. */
+    if ( strstr( filename, "../" ) != (char*) 0 )
+       return 0;
+
+#ifdef AUTH_FILE
+    /* Ensure that we are not reading a basic auth password file. */
+    fnl = strlen(filename);
+    if ( strcmp( filename, AUTH_FILE ) == 0 ||
+        ( fnl >= sizeof(AUTH_FILE) &&
+          strcmp( &filename[fnl - sizeof(AUTH_FILE) + 1], AUTH_FILE ) == 0 &&
+          filename[fnl - sizeof(AUTH_FILE)] == '/' ) )
+       return 0;
+
+    /* Check for an auth file in the same directory.  We can't do an actual
+    ** auth password check here because CGI programs are not given the
+    ** authorization header, for security reasons.  So instead we just
+    ** prohibit access to all auth-protected files.
+    */
+    dirname = strdup( filename );
+    if ( dirname == (char*) 0 )
+       return 0;       /* out of memory */
+    cp = strrchr( dirname, '/' );
+    if ( cp == (char*) 0 )
+       (void) strcpy( dirname, "." );
+    else
+       *cp = '\0';
+    authname = malloc( strlen( dirname ) + 1 + sizeof(AUTH_FILE) );
+    if ( authname == (char*) 0 )
+       return 0;       /* out of memory */
+    (void) sprintf( authname, "%s/%s", dirname, AUTH_FILE );
+    r = stat( authname, &sb2 );
+    free( dirname );
+    free( authname );
+    if ( r == 0 )
+       return 0;
+#endif /* AUTH_FILE */
+
+    /* Ensure that we are not reading a CGI file. */
+    if ( cgi_pattern != (char*) 0 && match( cgi_pattern, filename ) )
+       return 0;
+
+    return 1;
+    }
+
+
+static void
+show_time( time_t t, int gmt )
+    {
+    struct tm* tmP;
+    char tbuf[500];
+
+    if ( gmt )
+       tmP = gmtime( &t );
+    else
+       tmP = localtime( &t );
+    if ( strftime( tbuf, sizeof(tbuf), timefmt, tmP ) > 0 )
+       (void) fputs( tbuf, stdout );
+    }
+
+
+static void
+show_size( off_t size )
+    {
+    switch ( sizefmt )
+       {
+       case SF_BYTES:
+       (void) printf( "%ld", (long) size );  /* spec says should have commas */
+       break;
+       case SF_ABBREV:
+       if ( size < 1024 )
+           (void) printf( "%ld", (long) size );
+       else if ( size < 1024 )
+           (void) printf( "%ldK", (long) size / 1024L );
+       else if ( size < 1024*1024 )
+           (void) printf( "%ldM", (long) size / (1024L*1024L) );
+       else
+           (void) printf( "%ldG", (long) size / (1024L*1024L*1024L) );
+       break;
+       }
+    }
+
+
+static void
+do_config( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
+    {
+    /* The config directive controls various aspects of the file parsing.
+    ** There are two valid tags:
+    **   timefmt
+    **     Gives the server a new format to use when providing dates.  This
+    **     is a string compatible with the strftime library call.
+    **   sizefmt
+    **     Determines the formatting to be used when displaying the size of
+    **     a file.  Valid choices are bytes, for a formatted byte count
+    **     (formatted as 1,234,567), or abbrev for an abbreviated version
+    **     displaying the number of kilobytes or megabytes the file occupies.
+    */
+
+    if ( strcmp( tag, "timefmt" ) == 0 )
+       {
+       (void) strncpy( timefmt, val, sizeof(timefmt) - 1 );
+       timefmt[sizeof(timefmt) - 1] = '\0';
+       }
+    else if ( strcmp( tag, "sizefmt" ) == 0 )
+       {
+       if ( strcmp( val, "bytes" ) == 0 )
+           sizefmt = SF_BYTES;
+       else if ( strcmp( val, "abbrev" ) == 0 )
+           sizefmt = SF_ABBREV;
+       else
+           unknown_value( filename, directive, tag, val );
+       }
+    else
+       unknown_tag( filename, directive, tag );
+    }
+
+
+static void
+do_include( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
+    {
+    char vfilename2[1000];
+    char filename2[1000];
+    FILE* fp2;
+
+    /* Inserts the text of another document into the parsed document. */
+
+    if ( get_filename(
+            vfilename, filename, directive, tag, val, filename2,
+            sizeof(filename2) ) < 0 )
+       return;
+
+    if ( ! check_filename( filename2 ) )
+       {
+       not_permitted( directive, tag, filename2 );
+       return;
+       }
+
+    fp2 = fopen( filename2, "r" );
+    if ( fp2 == (FILE*) 0 )
+       {
+       not_found2( directive, tag, filename2 );
+       return;
+       }
+
+    if ( strcmp( tag, "virtual" ) == 0 )
+       {
+       if ( strlen( val ) < sizeof( vfilename2 ) )
+           (void) strcpy( vfilename2, val );
+       else
+           (void) strcpy( vfilename2, filename2 );  /* same size, has to fit */
+       }
+    else
+       {
+       if ( strlen( vfilename ) + 1 + strlen( val ) < sizeof(vfilename2) )
+           {
+           char* cp;
+           (void) strcpy( vfilename2, vfilename );
+           cp = strrchr( vfilename2, '/' );
+           if ( cp == (char*) 0 )
+               {
+               cp = &vfilename2[strlen( vfilename2 )];
+               *cp = '/';
+               }
+           (void) strcpy( ++cp, val );
+           }
+       else
+           (void) strcpy( vfilename2, filename2 );  /* same size, has to fit */
+       }
+
+    read_file( vfilename2, filename2, fp2 );
+    (void) fclose( fp2 );
+    }
+
+
+static void
+do_echo( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
+    {
+    char* cp;
+    time_t t;
+
+    /* Prints the value of one of the include variables.  Any dates are
+    ** printed subject to the currently configured timefmt.  The only valid
+    ** tag is var, whose value is the name of the variable you wish to echo.
+    */
+
+    if ( strcmp( tag, "var" ) != 0 )
+       unknown_tag( filename, directive, tag );
+    else
+       {
+       if ( strcmp( val, "DOCUMENT_NAME" ) == 0 )
+           {
+           /* The current filename. */
+           (void) fputs( filename, stdout );
+           }
+       else if ( strcmp( val, "DOCUMENT_URI" ) == 0 )
+           {
+           /* The virtual path to this file (such as /~robm/foo.shtml). */
+           (void) fputs( vfilename, stdout );
+           }
+       else if ( strcmp( val, "QUERY_STRING_UNESCAPED" ) == 0 )
+           {
+           /* The unescaped version of any search query the client sent. */
+           cp = getenv( "QUERY_STRING" );
+           if ( cp != (char*) 0 )
+               (void) fputs( cp, stdout );
+           }
+       else if ( strcmp( val, "DATE_LOCAL" ) == 0 )
+           {
+           /* The current date, local time zone. */
+           t = time( (time_t*) 0 );
+           show_time( t, 0 );
+           }
+       else if ( strcmp( val, "DATE_GMT" ) == 0 )
+           {
+           /* Same as DATE_LOCAL but in Greenwich mean time. */
+           t = time( (time_t*) 0 );
+           show_time( t, 1 );
+           }
+       else if ( strcmp( val, "LAST_MODIFIED" ) == 0 )
+           {
+           /* The last modification date of the current document. */
+           if ( fstat( fileno( fp ), &sb ) >= 0 )
+               show_time( sb.st_mtime, 0 );
+           }
+       else
+           {
+           /* Try an environment variable. */
+           cp = getenv( val );
+           if ( cp == (char*) 0 )
+               unknown_value( filename, directive, tag, val );
+           else
+               (void) fputs( cp, stdout );
+           }
+       }
+    }
+
+
+static void
+do_fsize( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
+    {
+    char filename2[1000];
+
+    /* Prints the size of the specified file. */
+
+    if ( get_filename(
+            vfilename, filename, directive, tag, val, filename2,
+            sizeof(filename2) ) < 0 )
+       return;
+    if ( stat( filename2, &sb ) < 0 )
+       {
+       not_found2( directive, tag, filename2 );
+       return;
+       }
+    show_size( sb.st_size );
+    }
+
+
+static void
+do_flastmod( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
+    {
+    char filename2[1000];
+
+    /* Prints the last modification date of the specified file. */
+
+    if ( get_filename(
+            vfilename, filename, directive, tag, val, filename2,
+            sizeof(filename2) ) < 0 )
+       return;
+    if ( stat( filename2, &sb ) < 0 )
+       {
+       not_found2( directive, tag, filename2 );
+       return;
+       }
+    show_time( sb.st_mtime, 0 );
+    }
+
+
+static void
+parse( char* vfilename, char* filename, FILE* fp, char* str )
+    {
+    char* directive;
+    char* cp;
+    int ntags;
+    char* tags[200];
+    int dirn;
+#define DI_CONFIG 0
+#define DI_INCLUDE 1
+#define DI_ECHO 2
+#define DI_FSIZE 3
+#define DI_FLASTMOD 4
+    int i;
+    char* val;
+
+    directive = str;
+    directive += strspn( directive, " \t\n\r" );
+
+    ntags = 0;
+    cp = directive;
+    for (;;)
+       {
+       cp = strpbrk( cp, " \t\n\r\"" );
+       if ( cp == (char*) 0 )
+           break;
+       if ( *cp == '"' )
+           {
+           cp = strpbrk( cp + 1, "\"" );
+           ++cp;
+           if ( *cp == '\0' )
+               break;
+           }
+       *cp++ = '\0';
+       cp += strspn( cp, " \t\n\r" );
+       if ( *cp == '\0' )
+           break;
+       if ( ntags < sizeof(tags)/sizeof(*tags) )
+           tags[ntags++] = cp;
+       }
+    
+    if ( strcmp( directive, "config" ) == 0 )
+       dirn = DI_CONFIG;
+    else if ( strcmp( directive, "include" ) == 0 )
+       dirn = DI_INCLUDE;
+    else if ( strcmp( directive, "echo" ) == 0 )
+       dirn = DI_ECHO;
+    else if ( strcmp( directive, "fsize" ) == 0 )
+       dirn = DI_FSIZE;
+    else if ( strcmp( directive, "flastmod" ) == 0 )
+       dirn = DI_FLASTMOD;
+    else
+       {
+       unknown_directive( filename, directive );
+       return;
+       }
+
+    for ( i = 0; i < ntags; ++i )
+       {
+       if ( i > 0 )
+           putchar( ' ' );
+       val = strchr( tags[i], '=' );
+       if ( val == (char*) 0 )
+           val = "";
+       else
+           *val++ = '\0';
+       if ( *val == '"' && val[strlen( val ) - 1] == '"' )
+           {
+           val[strlen( val ) - 1] = '\0';
+           ++val;
+           }
+       switch( dirn )
+           {
+           case DI_CONFIG:
+           do_config( vfilename, filename, fp, directive, tags[i], val );
+           break;
+           case DI_INCLUDE:
+           do_include( vfilename, filename, fp, directive, tags[i], val );
+           break;
+           case DI_ECHO:
+           do_echo( vfilename, filename, fp, directive, tags[i], val );
+           break;
+           case DI_FSIZE:
+           do_fsize( vfilename, filename, fp, directive, tags[i], val );
+           break;
+           case DI_FLASTMOD:
+           do_flastmod( vfilename, filename, fp, directive, tags[i], val );
+           break;
+           }
+       }
+    }
+
+
+static void
+slurp( char* vfilename, char* filename, FILE* fp )
+    {
+    char buf[1000];
+    int i;
+    int state;
+    int ich;
+
+    /* Now slurp in the rest of the comment from the input file. */
+    i = 0;
+    state = ST_GROUND;
+    while ( ( ich = getc( fp ) ) != EOF )
+       {
+       switch ( state )
+           {
+           case ST_GROUND:
+           if ( ich == '-' )
+               state = ST_MINUS1;
+           break;
+           case ST_MINUS1:
+           if ( ich == '-' )
+               state = ST_MINUS2;
+           else
+               state = ST_GROUND;
+           break;
+           case ST_MINUS2:
+           if ( ich == '>' )
+               {
+               buf[i - 2] = '\0';
+               parse( vfilename, filename, fp, buf );
+               return;
+               }
+           else if ( ich != '-' )
+               state = ST_GROUND;
+           break;
+           }
+       if ( i < sizeof(buf) - 1 )
+           buf[i++] = (char) ich;
+       }
+    }
+
+
+static void
+read_file( char* vfilename, char* filename, FILE* fp )
+    {
+    int ich;
+    int state;
+
+    /* Copy it to output, while running a state-machine to look for
+    ** SSI directives.
+    */
+    state = ST_GROUND;
+    while ( ( ich = getc( fp ) ) != EOF )
+       {
+       switch ( state )
+           {
+           case ST_GROUND:
+           if ( ich == '<' )
+               { state = ST_LESSTHAN; continue; }
+           break;
+           case ST_LESSTHAN:
+           if ( ich == '!' )
+               { state = ST_BANG; continue; }
+           else
+               { state = ST_GROUND; putchar( '<' ); }
+           break;
+           case ST_BANG:
+           if ( ich == '-' )
+               { state = ST_MINUS1; continue; }
+           else
+               { state = ST_GROUND; (void) fputs ( "<!", stdout ); }
+           break;
+           case ST_MINUS1:
+           if ( ich == '-' )
+               { state = ST_MINUS2; continue; }
+           else
+               { state = ST_GROUND; (void) fputs ( "<!-", stdout ); }
+           break;
+           case ST_MINUS2:
+           if ( ich == '#' )
+               {
+               slurp( vfilename, filename, fp );
+               state = ST_GROUND;
+               continue;
+               }
+           else
+               { state = ST_GROUND; (void) fputs ( "<!--", stdout ); }
+           break;
+           }
+       putchar( (char) ich );
+       }
+    }
+
+
+int
+main( int argc, char** argv )
+    {
+    char* script_name;
+    char* path_info;
+    char* path_translated;
+    FILE* fp;
+
+    argv0 = argv[0];
+
+    /* Default formats. */
+    (void) strcpy( timefmt, "%a %b %e %T %Z %Y" );
+    sizefmt = SF_BYTES;
+
+    /* The MIME type has to be text/html. */
+    (void) fputs( "Content-type: text/html\n\n", stdout );
+
+    /* Get the name that we were run as. */
+    script_name = getenv( "SCRIPT_NAME" );
+    if ( script_name == (char*) 0 )
+       {
+       internal_error( "Couldn't get SCRIPT_NAME environment variable." );
+       exit( 1 );
+       }
+
+    /* Append the PATH_INFO, if any, to get the full URL. */
+    path_info = getenv( "PATH_INFO" );
+    if ( path_info == (char*) 0 )
+       path_info = "";
+    url = (char*) malloc( strlen( script_name ) + strlen( path_info ) + 1 );
+    if ( url == (char*) 0 )
+       {
+       internal_error( "Out of memory." );
+       exit( 1 );
+       }
+    (void) sprintf( url, "%s%s", script_name, path_info );
+
+    /* Get the name of the file to parse. */
+    path_translated = getenv( "PATH_TRANSLATED" );
+    if ( path_translated == (char*) 0 )
+       {
+       internal_error( "Couldn't get PATH_TRANSLATED environment variable." );
+       exit( 1 );
+       }
+
+    if ( ! check_filename( path_translated ) )
+       {
+       not_permitted( "initial", "PATH_TRANSLATED", path_translated );
+       exit( 1 );
+       }
+
+    /* Open it. */
+    fp = fopen( path_translated, "r" );
+    if ( fp == (FILE*) 0 )
+       {
+       not_found( path_translated );
+       exit( 1 );
+       }
+
+    /* Read and handle the file. */
+    read_file( path_info, path_translated, fp );
+
+    (void) fclose( fp );
+    exit( 0 );
+    }
diff --git a/config.cache b/config.cache
new file mode 100644 (file)
index 0000000..a8615e8
--- /dev/null
@@ -0,0 +1,63 @@
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+ac_cv_acme_int64_t=${ac_cv_acme_int64_t='yes'}
+ac_cv_acme_socklen_t=${ac_cv_acme_socklen_t='yes'}
+ac_cv_acme_tm_has_tm_gmtoff=${ac_cv_acme_tm_has_tm_gmtoff='yes'}
+ac_cv_extern__progname=${ac_cv_extern__progname='yes'}
+ac_cv_func_atoll=${ac_cv_func_atoll='yes'}
+ac_cv_func_crypt=${ac_cv_func_crypt='no'}
+ac_cv_func_daemon=${ac_cv_func_daemon='yes'}
+ac_cv_func_gai_strerror=${ac_cv_func_gai_strerror='yes'}
+ac_cv_func_getaddrinfo=${ac_cv_func_getaddrinfo='yes'}
+ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname='yes'}
+ac_cv_func_getnameinfo=${ac_cv_func_getnameinfo='yes'}
+ac_cv_func_getpagesize=${ac_cv_func_getpagesize='yes'}
+ac_cv_func_hstrerror=${ac_cv_func_hstrerror='yes'}
+ac_cv_func_kqueue=${ac_cv_func_kqueue='no'}
+ac_cv_func_mmap_fixed_mapped=${ac_cv_func_mmap_fixed_mapped='yes'}
+ac_cv_func_poll=${ac_cv_func_poll='yes'}
+ac_cv_func_select=${ac_cv_func_select='yes'}
+ac_cv_func_setlogin=${ac_cv_func_setlogin='no'}
+ac_cv_func_setsid=${ac_cv_func_setsid='yes'}
+ac_cv_func_sigset=${ac_cv_func_sigset='yes'}
+ac_cv_func_socket=${ac_cv_func_socket='yes'}
+ac_cv_func_strerror=${ac_cv_func_strerror='yes'}
+ac_cv_func_vsnprintf=${ac_cv_func_vsnprintf='yes'}
+ac_cv_func_waitpid=${ac_cv_func_waitpid='yes'}
+ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h='yes'}
+ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h='yes'}
+ac_cv_header_grp_h=${ac_cv_header_grp_h='yes'}
+ac_cv_header_memory_h=${ac_cv_header_memory_h='yes'}
+ac_cv_header_osreldate_h=${ac_cv_header_osreldate_h='no'}
+ac_cv_header_paths_h=${ac_cv_header_paths_h='yes'}
+ac_cv_header_poll_h=${ac_cv_header_poll_h='yes'}
+ac_cv_header_sys_devpoll_h=${ac_cv_header_sys_devpoll_h='no'}
+ac_cv_header_sys_event_h=${ac_cv_header_sys_event_h='no'}
+ac_cv_header_sys_poll_h=${ac_cv_header_sys_poll_h='yes'}
+ac_cv_header_time=${ac_cv_header_time='yes'}
+ac_cv_header_unistd_h=${ac_cv_header_unistd_h='yes'}
+ac_cv_lbl_gcc_vers=${ac_cv_lbl_gcc_vers='6'}
+ac_cv_lbl_static_flag=${ac_cv_lbl_static_flag='unknown'}
+ac_cv_lib_crypt_crypt=${ac_cv_lib_crypt_crypt='yes'}
+ac_cv_lib_dir_opendir=${ac_cv_lib_dir_opendir='no'}
+ac_cv_lib_inet6_main=${ac_cv_lib_inet6_main='no'}
+ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'}
+ac_cv_prog_CC=${ac_cv_prog_CC='gcc'}
+ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
+ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross='no'}
+ac_cv_prog_cc_g=${ac_cv_prog_cc_g='yes'}
+ac_cv_prog_cc_works=${ac_cv_prog_cc_works='yes'}
+ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'}
+ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set='yes'}
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..2e9ad7f
--- /dev/null
@@ -0,0 +1,1462 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-10-02'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2016 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+       # If the system lacks a compiler, then just pick glibc.
+       # We could probably try harder.
+       LIBC=gnu
+
+       eval $set_cc_for_build
+       cat <<-EOF > $dummy.c
+       #include <features.h>
+       #if defined(__UCLIBC__)
+       LIBC=uclibc
+       #elif defined(__dietlibc__)
+       LIBC=dietlibc
+       #else
+       LIBC=gnu
+       #endif
+       EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+       ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+           /sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || \
+           echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           sh5el) machine=sh5le-unknown ;;
+           earmv*)
+               arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+               endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+               machine=${arch}${endian}-unknown
+               ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently (or will in the future) and ABI.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               os=netbsdelf
+               ;;
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep -q __ELF__
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # Determine ABI tags.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+               abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}${abi}"
+       exit ;;
+    *:Bitrig:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+       exit ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:LibertyBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    *:SolidBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:Sortix:*:*)
+       echo ${UNAME_MACHINE}-unknown-sortix
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE=alpha ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE=alpha ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE=alpha ;;
+           "EV5 (21164)")
+               UNAME_MACHINE=alphaev5 ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE=alphaev56 ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE=alphapca56 ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE=alphapca57 ;;
+           "EV6 (21264)")
+               UNAME_MACHINE=alphaev6 ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE=alphaev67 ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE=alphaev68 ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE=alphaev68 ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE=alphaev68 ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE=alphaev69 ;;
+           "EV7 (21364)")
+               UNAME_MACHINE=alphaev7 ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE=alphaev79 ;;
+       esac
+       # A Pn.n version is a patched version.
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+       exitcode=$?
+       trap '' 0
+       exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+       echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    s390x:SunOS:*:*)
+       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+       eval $set_cc_for_build
+       SUN_ARCH=i386
+       # If there is a compiler, see if it is configured for 64-bit objects.
+       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+       # This test works for both compilers.
+       if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               SUN_ARCH=x86_64
+           fi
+       fi
+       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+       echo m68k-milan-mint${UNAME_RELEASE}
+       exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+       echo m68k-hades-mint${UNAME_RELEASE}
+       exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+       echo m68k-unknown-mint${UNAME_RELEASE}
+       exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c &&
+         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`$dummy $dummyarg` &&
+           { echo "$SYSTEM_NAME"; exit; }
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit ;;
+    AViiON:dgux:*:*)
+       # DG/UX returns AViiON for all architectures
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+               then
+                       echo "$SYSTEM_NAME"
+               else
+                       echo rs6000-ibm-aix3.2.5
+               fi
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit ;;
+    *:AIX:*:[4567])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/lslpp ] ; then
+               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                   sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                   case "${sc_cpu_version}" in
+                     523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+                     528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+                     532)                      # CPU_PA_RISC2_0
+                       case "${sc_kernel_bits}" in
+                         32) HP_ARCH=hppa2.0n ;;
+                         64) HP_ARCH=hppa2.0w ;;
+                         '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
+                       esac ;;
+                   esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^            //' << EOF >$dummy.c
+
+               #define _HPUX_SOURCE
+               #include <stdlib.h>
+               #include <unistd.h>
+
+               int main ()
+               {
+               #if defined(_SC_KERNEL_BITS)
+                   long bits = sysconf(_SC_KERNEL_BITS);
+               #endif
+                   long cpu  = sysconf (_SC_CPU_VERSION);
+
+                   switch (cpu)
+                       {
+                       case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+                       case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+                       case CPU_PA_RISC2_0:
+               #if defined(_SC_KERNEL_BITS)
+                           switch (bits)
+                               {
+                               case 64: puts ("hppa2.0w"); break;
+                               case 32: puts ("hppa2.0n"); break;
+                               default: puts ("hppa2.0"); break;
+                               } break;
+               #else  /* !defined(_SC_KERNEL_BITS) */
+                           puts ("hppa2.0"); break;
+               #endif
+                       default: puts ("hppa1.0"); break;
+                       }
+                   exit (0);
+               }
+EOF
+                   (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = hppa2.0w ]
+       then
+           eval $set_cc_for_build
+
+           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+           # generating 64-bit code.  GNU and HP use different nomenclature:
+           #
+           # $ CC_FOR_BUILD=cc ./config.guess
+           # => hppa2.0w-hp-hpux11.23
+           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+           # => hppa64-hp-hpux11.23
+
+           if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+               grep -q __LP64__
+           then
+               HP_ARCH=hppa2.0w
+           else
+               HP_ARCH=hppa64
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+               { echo "$SYSTEM_NAME"; exit; }
+       echo unknown-hitachi-hiuxwe2
+       exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+       exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+       exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+       exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+       exit ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+       FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    5000:UNIX_System_V:4.*:*)
+       FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:FreeBSD:*:*)
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       case ${UNAME_PROCESSOR} in
+           amd64)
+               echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           *)
+               echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+       esac
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    *:MINGW64*:*)
+       echo ${UNAME_MACHINE}-pc-mingw64
+       exit ;;
+    *:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    *:MSYS*:*)
+       echo ${UNAME_MACHINE}-pc-msys
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    *:Interix*:*)
+       case ${UNAME_MACHINE} in
+           x86)
+               echo i586-pc-interix${UNAME_RELEASE}
+               exit ;;
+           authenticamd | genuineintel | EM64T)
+               echo x86_64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+           IA64)
+               echo ia64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+       esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit ;;
+    aarch64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    aarch64_be:Linux:*:*)
+       UNAME_MACHINE=aarch64_be
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+       esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    arm*:Linux:*:*)
+       eval $set_cc_for_build
+       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_EABI__
+       then
+           echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       else
+           if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+               | grep -q __ARM_PCS_VFP
+           then
+               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+           else
+               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+           fi
+       fi
+       exit ;;
+    avr32*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    cris:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+       exit ;;
+    crisv32:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+       exit ;;
+    e2k:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    frv:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    hexagon:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    i*86:Linux:*:*)
+       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    k1om:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=${UNAME_MACHINE}el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=${UNAME_MACHINE}
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+       ;;
+    mips64el:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    openrisc*:Linux:*:*)
+       echo or1k-unknown-linux-${LIBC}
+       exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    padre:Linux:*:*)
+       echo sparc-unknown-linux-${LIBC}
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-${LIBC}
+       exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+         PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+         *)    echo hppa-unknown-linux-${LIBC} ;;
+       esac
+       exit ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-${LIBC}
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-${LIBC}
+       exit ;;
+    ppc64le:Linux:*:*)
+       echo powerpc64le-unknown-linux-${LIBC}
+       exit ;;
+    ppcle:Linux:*:*)
+       echo powerpcle-unknown-linux-${LIBC}
+       exit ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    tile*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+       exit ;;
+    x86_64:Linux:*:*)
+       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+       exit ;;
+    xtensa*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+       # Unixware is an offshoot of SVR4, but it has its own version
+       # number series starting with 2...
+       # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+       # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+       # uname -m prints for DJGPP always 'pc', but it prints nothing about
+       # the processor, so we play safe by assuming i586.
+       # Note: whatever this is, it MUST be the same as what config.sub
+       # prints for the "djgpp" host, or else GDB configure will decide that
+       # this is a cross-build.
+       echo i586-pc-msdosdjgpp
+       exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+       OS_REL='.3'
+       test -r /etc/.relid \
+           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+           && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit ;;
+    PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                       # says <Richard.M.Bartel@ccMail.Census.GOV>
+       echo i586-unisys-sysv4
+       exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit ;;
+    i*86:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo ${UNAME_MACHINE}-stratus-vos
+       exit ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+       exit ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit ;;
+    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
+       echo i586-pc-haiku
+       exit ;;
+    x86_64:Haiku:*:*)
+       echo x86_64-unknown-haiku
+       exit ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-7:SUPER-UX:*:*)
+       echo sx7-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8:SUPER-UX:*:*)
+       echo sx8-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8R:SUPER-UX:*:*)
+       echo sx8r-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-ACE:SUPER-UX:*:*)
+       echo sxace-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       eval $set_cc_for_build
+       if test "$UNAME_PROCESSOR" = unknown ; then
+           UNAME_PROCESSOR=powerpc
+       fi
+       if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+           if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+               if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+                   grep IS_64BIT_ARCH >/dev/null
+               then
+                   case $UNAME_PROCESSOR in
+                       i386) UNAME_PROCESSOR=x86_64 ;;
+                       powerpc) UNAME_PROCESSOR=powerpc64 ;;
+                   esac
+               fi
+           fi
+       elif test "$UNAME_PROCESSOR" = i386 ; then
+           # Avoid executing cc on OS X 10.9, as it ships with a stub
+           # that puts up a graphical alert prompting to install
+           # developer tools.  Any system running Mac OS X 10.7 or
+           # later (Darwin 11 and later) is required to have a 64-bit
+           # processor. This is not true of the ARM version of Darwin
+           # that Apple uses in portable devices.
+           UNAME_PROCESSOR=x86_64
+       fi
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = x86; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+       echo neo-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = 386; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+       echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+    i*86:AROS:*:*)
+       echo ${UNAME_MACHINE}-pc-aros
+       exit ;;
+    x86_64:VMkernel:*:*)
+       echo ${UNAME_MACHINE}-unknown-esx
+       exit ;;
+    amd64:Isilon\ OneFS:*:*)
+       echo x86_64-unknown-onefs
+       exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.guess.dh-orig b/config.guess.dh-orig
new file mode 100755 (executable)
index 0000000..e9e4455
--- /dev/null
@@ -0,0 +1,693 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:*:*)
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'`
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-cbm-sysv4
+       exit 0;;
+    amiga:NetBSD:*:*)
+      echo m68k-cbm-netbsd${UNAME_RELEASE}
+      exit 0 ;;
+    amiga:OpenBSD:*:*)
+      echo m68k-cbm-openbsd${UNAME_RELEASE}
+      exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    Pyramid*:OSx*:*:*|MIS*:OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:NetBSD:*:*)
+       echo m68k-atari-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-atari-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3*:NetBSD:*:*)
+       echo m68k-sun-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-sun-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:NetBSD:*:*)
+       echo m68k-apple-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-apple-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >dummy.c
+       int main (argc, argv) int argc; char **argv; {
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       ${CC-cc} dummy.c -o dummy \
+         && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm dummy.c dummy && exit 0
+       rm -f dummy.c dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+        if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+       if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+            -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+       else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+       fi
+        else echo i586-dg-dgux${UNAME_RELEASE}
+        fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+               rm -f dummy.c dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:4)
+       if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=4.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[3478]??:HP-UX:*:*)
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;;
+           9000/8?? )            HP_ARCH=hppa1.0 ;;
+       esac
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+       rm -f dummy.c dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i?86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F300:UNIX_System_V:*:*)
+        FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    F301:UNIX_System_V:*:*)
+       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+       exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+       echo m68k-hp-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp3[0-9][05]:OpenBSD:*:*)
+       echo m68k-hp-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    i?86:BSD/386:*:* | *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:NetBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo i386-pc-cygwin32
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin32
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    *:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us.
+       ld_help_string=`ld --help 2>&1`
+       if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i.86"; then
+         echo "${UNAME_MACHINE}-pc-linux-gnu" ; exit 0
+       elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i.86linux"; then
+         echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0
+       elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i.86coff"; then
+         echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0
+       elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then
+         echo "${UNAME_MACHINE}-unknown-linux-gnu" ; exit 0
+       elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then
+         echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0
+       elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf32ppc"; then
+         echo "powerpc-unknown-linux-gnu" ; exit 0
+       elif test "${UNAME_MACHINE}" = "alpha" ; then
+         echo alpha-unknown-linux-gnu ; exit 0
+       elif test "${UNAME_MACHINE}" = "sparc" ; then
+         echo sparc-unknown-linux-gnu ; exit 0
+       else
+         # Either a pre-BFD a.out linker (linux-gnuoldld) or one that does not give us
+         # useful --help.  Gcc wants to distinguish between linux-gnuoldld and linux-gnuaout.
+         test ! -d /usr/lib/ldscripts/. \
+           && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+         # Determine whether the default compiler is a.out or elf
+         cat >dummy.c <<EOF
+main(argc, argv)
+int argc;
+char *argv[];
+{
+#ifdef __ELF__
+  printf ("%s-pc-linux-gnu\n", argv[1]);
+#else
+  printf ("%s-pc-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+         rm -f dummy.c dummy
+       fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i?86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i?86:LynxOS:2.*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..65ab1e3
--- /dev/null
+++ b/config.h
@@ -0,0 +1,392 @@
+/* config.h - configuration defines for thttpd and libhttpd
+**
+** Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+
+/* The following configuration settings are sorted in order of decreasing
+** likelihood that you'd want to change them - most likely first, least
+** likely last.
+**
+** In case you're not familiar with the convention, "#ifdef notdef"
+** is a Berkeleyism used to indicate temporarily disabled code.
+** The idea here is that you re-enable it by just moving it outside
+** of the ifdef.
+*/
+
+/* CONFIGURE: CGI programs must match this pattern to get executed.  It's
+** a simple shell-style wildcard pattern, with * meaning any string not
+** containing a slash, ** meaning any string at all, and ? meaning any
+** single character; or multiple such patterns separated by |.  The
+** patterns get checked against the filename part of the incoming URL.
+**
+** Restricting CGI programs to a single directory lets the site administrator
+** review them for security holes, and is strongly recommended.  If there
+** are individual users that you trust, you can enable their directories too.
+**
+** You can also specify a CGI pattern on the command line, with the -c flag.
+** Such a pattern overrides this compiled-in default.
+**
+** If no CGI pattern is specified, neither here nor on the command line,
+** then CGI programs cannot be run at all.  If you want to disable CGI
+** as a security measure that's how you do it, just don't define any
+** pattern here and don't run with the -c flag.
+*/
+#ifdef notdef
+/* Some sample patterns.  Allow programs only in one central directory: */
+#define CGI_PATTERN "/cgi-bin/*"
+/* Allow programs in a central directory, or anywhere in a trusted
+** user's tree: */
+#define CGI_PATTERN "/cgi-bin/*|/jef/**"
+/* Allow any program ending with a .cgi: */
+#define CGI_PATTERN "**.cgi"
+/* When virtual hosting, enable the central directory on every host: */
+#define CGI_PATTERN "/*/cgi-bin/*"
+#endif
+
+/* CONFIGURE: How many seconds to allow CGI programs to run before killing
+** them.  This is in case someone writes a CGI program that goes into an
+** infinite loop, or does a massive database lookup that would take hours,
+** or whatever.  If you don't want any limit, comment this out, but that's
+** probably a really bad idea.
+*/
+#define CGI_TIMELIMIT 30
+
+/* CONFIGURE: Maximum number of simultaneous CGI programs allowed.
+** If this many are already running, then attempts to run more will
+** return an HTTP 503 error.  If this is not defined then there's
+** no limit (and you'd better have a lot of memory).  This can also be
+** set in the runtime config file.
+*/
+#ifdef notdef
+#define CGI_LIMIT 50
+#endif
+
+/* CONFIGURE: How many seconds to allow for reading the initial request
+** on a new connection.
+*/
+#define IDLE_READ_TIMELIMIT 60
+
+/* CONFIGURE: How many seconds before an idle connection gets closed.
+*/
+#define IDLE_SEND_TIMELIMIT 300
+
+/* CONFIGURE: The syslog facility to use.  Using this you can set up your
+** syslog.conf so that all thttpd messages go into a separate file.  Note
+** that even if you use the -l command line flag to send logging to a
+** file, errors still get sent via syslog.
+*/
+#define LOG_FACILITY LOG_DAEMON
+
+/* CONFIGURE: Tilde mapping.  Many URLs use ~username to indicate a
+** user's home directory.  thttpd provides two options for mapping
+** this construct to an actual filename.
+**
+** 1) Map ~username to <prefix>/username.  This is the recommended choice.
+** Each user gets a subdirectory in the main chrootable web tree, and
+** the tilde construct points there.  The prefix could be something
+** like "users", or it could be empty.  See also the makeweb program
+** for letting users create their own web subdirectories.
+**
+** 2) Map ~username to <user's homedir>/<postfix>.  The postfix would be
+** the name of a subdirectory off of the user's actual home dir, something
+** like "public_html".  This is what Apache and other servers do.  The problem
+** is, you can't do this and chroot() at the same time, so it's inherently
+** a security hole.  This is strongly dis-recommended, but it's here because
+** some people really want it.  Use at your own risk.
+**
+** You can also leave both options undefined, and thttpd will not do
+** anything special about tildes.  Enabling both options is an error.
+*/
+#ifdef notdef
+#define TILDE_MAP_1 "users"
+#define TILDE_MAP_2 "public_html"
+#endif
+
+/* CONFIGURE: The file to use for authentication.  If this is defined then
+** thttpd checks for this file in the local directory before every fetch.
+** If the file exists then authentication is done, otherwise the fetch
+** proceeds as usual.
+**
+** If you undefine this then thttpd will not implement authentication
+** at all and will not check for auth files, which saves a bit of CPU time.
+*/
+#define AUTH_FILE ".htpasswd"
+
+/* CONFIGURE: The default character set name to use with text MIME types.
+** This gets substituted into the MIME types where they have a "%s".
+**
+** You can override this in the config file with the "charset" setting,
+** or on the command like with the -T flag.
+*/
+#define DEFAULT_CHARSET "UTF-8"
+
+
+/* Most people won't want to change anything below here. */
+
+/* CONFIGURE: This controls the SERVER_NAME environment variable that gets
+** passed to CGI programs.  By default thttpd does a gethostname(), which
+** gives the host's canonical name.  If you want to always use some other name
+** you can define it here.
+**
+** Alternately, if you want to run the same thttpd binary on multiple
+** machines, and want to build in alternate names for some or all of
+** them, you can define a list of canonical name to altername name
+** mappings.  thttpd seatches the list and when it finds a match on
+** the canonical name, that alternate name gets used.  If no match
+** is found, the canonical name gets used.
+**
+** If both SERVER_NAME and SERVER_NAME_LIST are defined here, thttpd searches
+** the list as above, and if no match is found then SERVER_NAME gets used.
+**
+** In any case, if thttpd is started with the -h flag, that name always
+** gets used.
+*/
+#ifdef notdef
+#define SERVER_NAME "your.hostname.here"
+#define SERVER_NAME_LIST \
+    "canonical.name.here/alternate.name.here", \
+    "canonical.name.two/alternate.name.two"
+#endif
+
+/* CONFIGURE: Undefine this if you want thttpd to hide its specific version
+** when returning into to browsers.  Instead it'll just say "thttpd" with
+** no version.
+*/
+#define SHOW_SERVER_VERSION
+
+/* CONFIGURE: Define this if you want to always chroot(), without having
+** to give the -r command line flag.  Some people like this as a security
+** measure, to prevent inadvertant exposure by accidentally running without -r.
+** You can still disable it at runtime with the -nor flag.
+*/
+#ifdef notdef
+#define ALWAYS_CHROOT
+#endif
+
+/* CONFIGURE: Define this if you want to always do virtual hosting, without
+** having to give the -v command line flag.  You can still disable it at
+** runtime with the -nov flag.
+*/
+#ifdef notdef
+#define ALWAYS_VHOST
+#endif
+
+/* CONFIGURE: If you're using the vhost feature and you have a LOT of
+** virtual hostnames (like, hundreds or thousands), you will want to
+** enable this feature.  It avoids a problem with most Unix filesystems,
+** where if there are a whole lot of items in a directory then name lookup
+** becomes very slow.  This feature makes thttpd use subdirectories
+** based on the first characters of each hostname.  You can set it to use
+** from one to three characters.  If the hostname starts with "www.", that
+** part is skipped over.  Dots are also skipped over, and if the name isn't
+** long enough then "_"s are used.  Here are some examples of how hostnames
+** would get turned into directory paths, for each different setting:
+** 1: www.acme.com ->    a/www.acme.com
+** 1: foobar.acme.com -> f/foobar.acme.com
+** 2: www.acme.com ->    a/c/www.acme.com
+** 2: foobar.acme.com -> f/o/foobar.acme.com
+** 3: www.acme.com ->    a/c/m/www.acme.com
+** 3: foobar.acme.com -> f/o/o/foobar.acme.com
+** 3: m.tv ->            m/t/v/m.tv
+** 4: m.tv ->            m/t/v/_/m.tv
+** Note that if you compile this setting in but then forget to set up
+** the corresponding subdirectories, the only error indication you'll
+** get is a "404 Not Found" when you try to visit a site.  So be careful.
+*/
+#ifdef notdef
+#define VHOST_DIRLEVELS 1
+#define VHOST_DIRLEVELS 2
+#define VHOST_DIRLEVELS 3
+#endif
+
+/* CONFIGURE: Define this if you want to always use a global passwd file,
+** without having to give the -P command line flag.  You can still disable
+** it at runtime with the -noP flag.
+*/
+#ifdef notdef
+#define ALWAYS_GLOBAL_PASSWD
+#endif
+
+/* CONFIGURE: When started as root, the default username to switch to after
+** initializing.  If this user (or the one specified by the -u flag) does
+** not exist, the program will refuse to run.
+*/
+#define DEFAULT_USER "nobody"
+
+/* CONFIGURE: When started as root, the program can automatically chdir()
+** to the home directory of the user specified by -u or DEFAULT_USER.
+** An explicit -d still overrides this.
+*/
+#ifdef notdef
+#define USE_USER_DIR
+#endif
+
+/* CONFIGURE: If this is defined, some of the built-in error pages will
+** have more explicit information about exactly what the problem is.
+** Some sysadmins don't like this, for security reasons.
+*/
+#define EXPLICIT_ERROR_PAGES
+
+/* CONFIGURE: Subdirectory for custom error pages.  The error filenames are
+** $WEBDIR/$ERR_DIR/err%d.html - if virtual hosting is enabled then
+** $WEBDIR/hostname/$ERR_DIR/err%d.html is searched first.  This allows
+** different custom error pages for each virtual hosting web server.  If
+** no custom page for a given error can be found, the built-in error page
+** is generated.  If ERR_DIR is not defined at all, only the built-in error
+** pages will be generated.
+*/
+#define ERR_DIR "errors"
+
+/* CONFIGURE: Define this if you want a standard HTML tail containing
+** $SERVER_SOFTWARE and $SERVER_ADDRESS to be appended to the custom error
+** pages.  (It is always appended to the built-in error pages.)
+*/
+#define ERR_APPEND_SERVER_INFO
+
+/* CONFIGURE: nice(2) value to use for CGI programs.  If this is undefined,
+** CGI programs run at normal priority.
+*/
+#define CGI_NICE 10
+
+/* CONFIGURE: $PATH to use for CGI programs.
+*/
+#define CGI_PATH "/usr/local/bin:/usr/ucb:/bin:/usr/bin"
+
+/* CONFIGURE: If defined, $LD_LIBRARY_PATH to use for CGI programs.
+*/
+#ifdef notdef
+#define CGI_LD_LIBRARY_PATH "/usr/local/lib:/usr/lib"
+#endif
+
+/* CONFIGURE: How often to run the occasional cleanup job.
+*/
+#define OCCASIONAL_TIME 120
+
+/* CONFIGURE: Seconds between stats syslogs.  If this is undefined then
+** no stats are accumulated and no stats syslogs are done.
+*/
+#define STATS_TIME 3600
+
+/* CONFIGURE: The mmap cache tries to keep the total number of mapped
+** files below this number, so you don't run out of kernel file descriptors.
+** If you have reconfigured your kernel to have more descriptors, you can
+** raise this and thttpd will keep more maps cached.  However it's not
+** a hard limit, thttpd will go over it if you really are accessing
+** a whole lot of files.
+*/
+#define DESIRED_MAX_MAPPED_FILES 1000
+
+/* CONFIGURE: The mmap cache also tries to keep the total mapped bytes
+** below this number, so you don't run out of address space.  Again
+** it's not a hard limit, thttpd will go over it if you really are
+** accessing a bunch of large files.
+*/
+#define DESIRED_MAX_MAPPED_BYTES 1000000000
+
+
+/* You almost certainly don't want to change anything below here. */
+
+/* CONFIGURE: When throttling CGI programs, we don't know how many bytes
+** they send back to the client because it would be inefficient to
+** interpose a counter.  CGI programs are much more expensive than
+** regular files to serve, so we set an arbitrary and high byte count
+** that gets applied to all CGI programs for throttling purposes.
+*/
+#define CGI_BYTECOUNT 25000
+
+/* CONFIGURE: The default port to listen on.  80 is the standard HTTP port.
+*/
+#define DEFAULT_PORT 80
+
+/* CONFIGURE: A list of index filenames to check.  The files are searched
+** for in this order.
+*/
+#define INDEX_NAMES "index.html", "index.htm", "index.xhtml", "index.xht", "Default.htm", "index.cgi"
+
+/* CONFIGURE: If this is defined then thttpd will automatically generate
+** index pages for directories that don't have an explicit index file.
+** If you want to disable this behavior site-wide, perhaps for security
+** reasons, just undefine this.  Note that you can disable indexing of
+** individual directories by merely doing a "chmod 711" on them - the
+** standard Unix file permission to allow file access but disable "ls".
+*/
+#define GENERATE_INDEXES
+
+/* CONFIGURE: Whether to log unknown request headers.  Most sites will not
+** want to log them, which will save them a bit of CPU time.
+*/
+#ifdef notdef
+#define LOG_UNKNOWN_HEADERS
+#endif
+
+/* CONFIGURE: Whether to fflush() the log file after each request.  If
+** this is turned off there's a slight savings in CPU cycles.
+*/
+#define FLUSH_LOG_EVERY_TIME
+
+/* CONFIGURE: Time between updates of the throttle table's rolling averages. */
+#define THROTTLE_TIME 2
+
+/* CONFIGURE: The listen() backlog queue length.  The 1024 doesn't actually
+** get used, the kernel uses its maximum allowed value.  This is a config
+** parameter only in case there's some OS where asking for too high a queue
+** length causes an error.  Note that on many systems the maximum length is
+** way too small - see http://www.acme.com/software/thttpd/notes.html
+*/
+#define LISTEN_BACKLOG 1024
+
+/* CONFIGURE: Maximum number of throttle patterns that any single URL can
+** be included in.  This has nothing to do with the number of throttle
+** patterns that you can define, which is unlimited.
+*/
+#define MAXTHROTTLENUMS 10
+
+/* CONFIGURE: Number of file descriptors to reserve for uses other than
+** connections.  Currently this is 10, representing one for the listen fd,
+** one for dup()ing at connection startup time, one for reading the file,
+** one for syslog, and possibly one for the regular log file, which is
+** five, plus a factor of two for who knows what.
+*/
+#define SPARE_FDS 10
+
+/* CONFIGURE: How many milliseconds to leave a connection open while doing a
+** lingering close.
+*/
+#define LINGER_TIME 500
+
+/* CONFIGURE: Maximum number of symbolic links to follow before
+** assuming there's a loop.
+*/
+#define MAX_LINKS 32
+
+/* CONFIGURE: You don't even want to know.
+*/
+#define MIN_WOULDBLOCK_DELAY 100L
+
+#endif /* _CONFIG_H_ */
diff --git a/config.log b/config.log
new file mode 100644 (file)
index 0000000..597fcbf
--- /dev/null
@@ -0,0 +1,306 @@
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+configure:573: checking host system type
+configure:594: checking target system type
+configure:612: checking build system type
+configure:638: checking for gcc
+configure:751: checking whether the C compiler (gcc -g -O2 ) works
+configure:767: gcc -o conftest -g -O2   conftest.c  1>&5
+configure:764:1: warning: return type defaults to 'int' [-Wimplicit-int]
+ main(){return(0);}
+ ^~~~
+configure:793: checking whether the C compiler (gcc -g -O2 ) is a cross-compiler
+configure:798: checking whether we are using GNU C
+configure:807: gcc -E conftest.c
+configure:826: checking whether gcc accepts -g
+configure:861: checking gcc version
+configure:879: checking how to link static binaries
+configure:910: checking for __progname
+configure:923: gcc -o conftest -g -O2   conftest.c  1>&5
+configure: In function 'main':
+configure:919:2: warning: implicit declaration of function 'puts' [-Wimplicit-function-declaration]
+  puts(__progname)
+  ^~~~
+configure:946: checking how to run the C preprocessor
+configure:967: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for fcntl.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for grp.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for memory.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for paths.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for poll.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for sys/poll.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1029: checking for sys/devpoll.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1035:25: fatal error: sys/devpoll.h: No such file or directory
+ #include <$ac_hdr>
+                         ^
+compilation terminated.
+configure: failed program was:
+#line 1034 "configure"
+#include "confdefs.h"
+#include <sys/devpoll.h>
+configure:1029: checking for sys/event.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1035:23: fatal error: sys/event.h: No such file or directory
+ #include <$ac_hdr>
+                       ^
+compilation terminated.
+configure: failed program was:
+#line 1034 "configure"
+#include "confdefs.h"
+#include <sys/event.h>
+configure:1029: checking for osreldate.h
+configure:1039: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1035:23: fatal error: osreldate.h: No such file or directory
+ #include <$ac_hdr>
+                       ^
+compilation terminated.
+configure: failed program was:
+#line 1034 "configure"
+#include "confdefs.h"
+#include <osreldate.h>
+configure:1066: checking whether time.h and sys/time.h may both be included
+configure:1080: gcc -c -g -O2  conftest.c 1>&5
+configure:1105: checking for dirent.h that defines DIR
+configure:1118: gcc -c -g -O2  conftest.c 1>&5
+configure:1143: checking for opendir in -ldir
+configure:1162: gcc -o conftest -g -O2   conftest.c -ldir   1>&5
+/usr/bin/ld: cannot find -ldir
+collect2: error: ld returned 1 exit status
+configure: failed program was:
+#line 1151 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+configure:1228: checking for /usr/local/v6/lib
+configure:1238: checking for gethostbyname
+configure:1266: gcc -o conftest -g -O2   conftest.c  1>&5
+configure:1451: checking for socket
+configure:1479: gcc -o conftest -g -O2   conftest.c  1>&5
+configure:1580: checking for main in -linet6
+configure:1595: gcc -o conftest -g -O2   conftest.c -linet6   1>&5
+/usr/bin/ld: cannot find -linet6
+collect2: error: ld returned 1 exit status
+configure: failed program was:
+#line 1588 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+configure:1624: checking for crypt
+configure:1652: gcc -o conftest -g -O2   conftest.c  1>&5
+/tmp/cc83IuJy.o: In function `main':
+/home/ralph/src/thttpd/thttpd-2.29/configure:1646: undefined reference to `crypt'
+collect2: error: ld returned 1 exit status
+configure: failed program was:
+#line 1629 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char crypt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char crypt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_crypt) || defined (__stub___crypt)
+choke me
+#else
+crypt();
+#endif
+
+; return 0; }
+configure:1670: checking for crypt in -lcrypt
+configure:1689: gcc -o conftest -g -O2   conftest.c -lcrypt   1>&5
+configure:1719: checking for hstrerror
+configure:1747: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1810: checking for strerror
+configure:1838: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for waitpid
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for vsnprintf
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1879:6: warning: conflicting types for built-in function 'vsnprintf'
+ char $ac_func();
+      ^~~~~~~~~
+configure:1867: checking for daemon
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for setsid
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for setlogin
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure: In function 'main':
+configure:1887:1: error: unknown type name 'choke'
+ choke me
+ ^~~~~
+configure: failed program was:
+#line 1872 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setlogin(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setlogin();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setlogin) || defined (__stub___setlogin)
+choke me
+#else
+setlogin();
+#endif
+
+; return 0; }
+configure:1867: checking for getaddrinfo
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for getnameinfo
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for gai_strerror
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for kqueue
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+/tmp/cccBW2WQ.o: In function `main':
+/home/ralph/src/thttpd/thttpd-2.29/configure:1889: undefined reference to `kqueue'
+collect2: error: ld returned 1 exit status
+configure: failed program was:
+#line 1872 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char kqueue(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char kqueue();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_kqueue) || defined (__stub___kqueue)
+choke me
+#else
+kqueue();
+#endif
+
+; return 0; }
+configure:1867: checking for sigset
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1867: checking for atoll
+configure:1895: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:1923: checking for unistd.h
+configure:1933: gcc -E  conftest.c >/dev/null 2>conftest.out
+configure:1962: checking for getpagesize
+configure:1990: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:2015: checking for working mmap
+configure:2163: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:2094:7: warning: conflicting types for built-in function 'malloc'
+ char *malloc();
+       ^~~~~~
+configure: In function 'main':
+configure:2104:13: warning: implicit declaration of function 'getpagesize' [-Wimplicit-function-declaration]
+  pagesize = getpagesize();
+             ^~~~~~~~~~~
+configure:2111:3: warning: implicit declaration of function 'exit' [-Wimplicit-function-declaration]
+   exit(1);
+   ^~~~
+configure:2111:3: warning: incompatible implicit declaration of built-in function 'exit'
+configure:2111:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2113:17: warning: implicit declaration of function 'rand' [-Wimplicit-function-declaration]
+   *(data + i) = rand();
+                 ^~~~
+configure:2114:2: warning: implicit declaration of function 'umask' [-Wimplicit-function-declaration]
+  umask(0);
+  ^~~~~
+configure:2117:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2117:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2118:6: warning: implicit declaration of function 'write' [-Wimplicit-function-declaration]
+  if (write(fd, data, pagesize) != pagesize)
+      ^~~~~
+configure:2119:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2119:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2120:2: warning: implicit declaration of function 'close' [-Wimplicit-function-declaration]
+  close(fd);
+  ^~~~~
+configure:2129:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2129:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2132:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2132:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2133:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
+  data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1);
+                        ^
+configure:2136:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2136:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2139:4: warning: incompatible implicit declaration of built-in function 'exit'
+    exit(1);
+    ^~~~
+configure:2139:4: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2150:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2150:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2151:6: warning: implicit declaration of function 'read' [-Wimplicit-function-declaration]
+  if (read(fd, data3, pagesize) != pagesize)
+      ^~~~
+configure:2152:3: warning: incompatible implicit declaration of built-in function 'exit'
+   exit(1);
+   ^~~~
+configure:2152:3: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2155:4: warning: incompatible implicit declaration of built-in function 'exit'
+    exit(1);
+    ^~~~
+configure:2155:4: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2157:2: warning: implicit declaration of function 'unlink' [-Wimplicit-function-declaration]
+  unlink("conftestmmap");
+  ^~~~~~
+configure:2158:2: warning: incompatible implicit declaration of built-in function 'exit'
+  exit(0);
+  ^~~~
+configure:2158:2: note: include '<stdlib.h>' or provide a declaration of 'exit'
+configure:2248: checking for select
+configure:2276: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:2248: checking for poll
+configure:2276: gcc -o conftest -g -O2   conftest.c -lcrypt  1>&5
+configure:2304: checking if struct tm has tm_gmtoff member
+configure:2318: gcc -c -g -O2  conftest.c 1>&5
+configure:2338: checking if int64_t exists
+configure:2351: gcc -c -g -O2  conftest.c 1>&5
+configure:2371: checking if socklen_t exists
+configure:2385: gcc -c -g -O2  conftest.c 1>&5
+configure:2406: checking whether make sets ${MAKE}
+configure:2444: checking for a BSD compatible install
diff --git a/config.status b/config.status
new file mode 100755 (executable)
index 0000000..acaced5
--- /dev/null
@@ -0,0 +1,180 @@
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host stolpe:
+#
+# ./configure  --build=x86_64-linux-gnu --prefix=/usr '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' --sysconfdir=/etc --localstatedir=/var --disable-silent-rules '--libdir=${prefix}/lib/x86_64-linux-gnu' '--libexecdir=${prefix}/lib/x86_64-linux-gnu' --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr/local --mandir=/usr/local/man
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running ${CONFIG_SHELL-/bin/sh} ./configure  --build=x86_64-linux-gnu --prefix=/usr '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' --sysconfdir=/etc --localstatedir=/var --disable-silent-rules '--libdir=${prefix}/lib/x86_64-linux-gnu' '--libexecdir=${prefix}/lib/x86_64-linux-gnu' --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr/local --mandir=/usr/local/man --no-create --no-recursion"
+    exec ${CONFIG_SHELL-/bin/sh} ./configure  --build=x86_64-linux-gnu --prefix=/usr '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' --sysconfdir=/etc --localstatedir=/var --disable-silent-rules '--libdir=${prefix}/lib/x86_64-linux-gnu' '--libexecdir=${prefix}/lib/x86_64-linux-gnu' --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr/local --mandir=/usr/local/man --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "./config.status generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "$ac_cs_usage"; exit 0 ;;
+  *) echo "$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=.
+ac_given_INSTALL="/usr/bin/install -c"
+
+trap 'rm -fr Makefile cgi-src/Makefile extras/Makefile conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+/^[    ]*VPATH[        ]*=[^:]*$/d
+
+s%@SHELL@%/bin/sh%g
+s%@CFLAGS@%-g -O2%g
+s%@CPPFLAGS@%%g
+s%@CXXFLAGS@%-g -O2%g
+s%@FFLAGS@%-g -O2%g
+s%@DEFS@% -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 %g
+s%@LDFLAGS@%%g
+s%@LIBS@%-lcrypt %g
+s%@exec_prefix@%${prefix}%g
+s%@prefix@%/usr/local%g
+s%@program_transform_name@%s,x,x,%g
+s%@bindir@%${exec_prefix}/bin%g
+s%@sbindir@%${exec_prefix}/sbin%g
+s%@libexecdir@%${prefix}/lib/x86_64-linux-gnu%g
+s%@datadir@%${prefix}/share%g
+s%@sysconfdir@%/etc%g
+s%@sharedstatedir@%${prefix}/com%g
+s%@localstatedir@%/var%g
+s%@libdir@%${prefix}/lib/x86_64-linux-gnu%g
+s%@includedir@%${prefix}/include%g
+s%@oldincludedir@%/usr/include%g
+s%@infodir@%${prefix}/share/info%g
+s%@mandir@%/usr/local/man%g
+s%@host@%x86_64-pc-linux-gnu%g
+s%@host_alias@%x86_64-pc-linux-gnu%g
+s%@host_cpu@%x86_64%g
+s%@host_vendor@%pc%g
+s%@host_os@%linux-gnu%g
+s%@target@%x86_64-pc-linux-gnu%g
+s%@target_alias@%x86_64-pc-linux-gnu%g
+s%@target_cpu@%x86_64%g
+s%@target_vendor@%pc%g
+s%@target_os@%linux-gnu%g
+s%@build@%x86_64-pc-linux-gnu%g
+s%@build_alias@%x86_64-linux-gnu%g
+s%@build_cpu@%x86_64%g
+s%@build_vendor@%pc%g
+s%@build_os@%linux-gnu%g
+s%@CC@%gcc%g
+s%@CPP@%gcc -E%g
+s%@LIBOBJS@%%g
+s%@SET_MAKE@%%g
+s%@INSTALL_PROGRAM@%${INSTALL}%g
+s%@INSTALL_SCRIPT@%${INSTALL_PROGRAM}%g
+s%@INSTALL_DATA@%${INSTALL} -m 644%g
+s%@V_CCOPT@%-O2%g
+s%@V_STATICFLAG@%%g
+s%@V_NETLIBS@%%g
+
+CEOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+
+CONFIG_FILES=${CONFIG_FILES-"Makefile cgi-src/Makefile extras/Makefile"}
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+
+
+exit 0
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..dd2ca93
--- /dev/null
@@ -0,0 +1,1825 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-11-04'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2016 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | cloudabi*-eabi* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis | -knuth | -cray | -microblaze*)
+               os=
+               basic_machine=$1
+               ;;
+       -bluegene*)
+               os=-cnk
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*178)
+               os=-lynxos178
+               ;;
+       -lynx*5)
+               os=-lynxos5
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | aarch64 | aarch64_be \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arceb \
+       | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+       | avr | avr32 \
+       | ba \
+       | be32 | be64 \
+       | bfin \
+       | c4x | c8051 | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | e2k | epiphany \
+       | fido | fr30 | frv | ft32 \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | hexagon \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | k1om \
+       | le32 | le64 \
+       | lm32 \
+       | m32c | m32r | m32rle | m68000 | m68k | m88k \
+       | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64octeon | mips64octeonel \
+       | mips64orion | mips64orionel \
+       | mips64r5900 | mips64r5900el \
+       | mips64vr | mips64vrel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa32r6 | mipsisa32r6el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64r6 | mipsisa64r6el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipsr5900 | mipsr5900el \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | moxie \
+       | mt \
+       | msp430 \
+       | nds32 | nds32le | nds32be \
+       | nios | nios2 | nios2eb | nios2el \
+       | ns16k | ns32k \
+       | open8 | or1k | or1knd | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle \
+       | pru \
+       | pyramid \
+       | riscv32 | riscv64 \
+       | rl78 | rx \
+       | score \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu \
+       | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+       | ubicom32 \
+       | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+       | visium \
+       | we32k \
+       | x86 | xc16x | xstormy16 | xtensa \
+       | z8k | z80)
+               basic_machine=$basic_machine-unknown
+               ;;
+       c54x)
+               basic_machine=tic54x-unknown
+               ;;
+       c55x)
+               basic_machine=tic55x-unknown
+               ;;
+       c6x)
+               basic_machine=tic6x-unknown
+               ;;
+       leon|leon[3-9])
+               basic_machine=sparc-$basic_machine
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       strongarm | thumb | xscale)
+               basic_machine=arm-unknown
+               ;;
+       xgate)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       xscaleeb)
+               basic_machine=armeb-unknown
+               ;;
+
+       xscaleel)
+               basic_machine=armel-unknown
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | aarch64-* | aarch64_be-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* | avr32-* \
+       | ba-* \
+       | be32-* | be64-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* \
+       | c8051-* | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | e2k-* | elxsi-* \
+       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | hexagon-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | k1om-* \
+       | le32-* | le64-* \
+       | lm32-* \
+       | m32c-* | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+       | microblaze-* | microblazeel-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64octeon-* | mips64octeonel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64r5900-* | mips64r5900el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa32r6-* | mipsisa32r6el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64r6-* | mipsisa64r6el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipsr5900-* | mipsr5900el-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | nds32-* | nds32le-* | nds32be-* \
+       | nios-* | nios2-* | nios2eb-* | nios2el-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | open8-* \
+       | or1k*-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+       | pru-* \
+       | pyramid-* \
+       | riscv32-* | riscv64-* \
+       | rl78-* | romp-* | rs6000-* | rx-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+       | tahoe-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tile*-* \
+       | tron-* \
+       | ubicom32-* \
+       | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+       | vax-* \
+       | visium-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xc16x-* | xps100-* \
+       | xstormy16-* | xtensa*-* \
+       | ymp-* \
+       | z8k-* | z80-*)
+               ;;
+       # Recognize the basic CPU types without company name, with glob match.
+       xtensa*)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aros)
+               basic_machine=i386-pc
+               os=-aros
+               ;;
+       asmjs)
+               basic_machine=asmjs-unknown
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       blackfin)
+               basic_machine=bfin-unknown
+               os=-linux
+               ;;
+       blackfin-*)
+               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
+       c54x-*)
+               basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c55x-*)
+               basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c6x-*)
+               basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       cegcc)
+               basic_machine=arm-unknown
+               os=-cegcc
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16 | cr16-*)
+               basic_machine=cr16-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dicos)
+               basic_machine=i686-pc
+               os=-dicos
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       e500v[12])
+               basic_machine=powerpc-unknown
+               os=$os"spe"
+               ;;
+       e500v[12]-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=$os"spe"
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       leon-*|leon[3-9]-*)
+               basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+               ;;
+       m68knommu)
+               basic_machine=m68k-unknown
+               os=-linux
+               ;;
+       m68knommu-*)
+               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       microblaze*)
+               basic_machine=microblaze-xilinx
+               ;;
+       mingw64)
+               basic_machine=x86_64-pc
+               os=-mingw64
+               ;;
+       mingw32)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       mingw32ce)
+               basic_machine=arm-unknown
+               os=-mingw32ce
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       moxiebox)
+               basic_machine=moxie-unknown
+               os=-moxiebox
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       msys)
+               basic_machine=i686-pc
+               os=-msys
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       nacl)
+               basic_machine=le32-unknown
+               os=-nacl
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       neo-tandem)
+               basic_machine=neo-tandem
+               ;;
+       nse-tandem)
+               basic_machine=nse-tandem
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       parisc)
+               basic_machine=hppa-unknown
+               os=-linux
+               ;;
+       parisc-*)
+               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc | ppcbe)    basic_machine=powerpc-unknown
+               ;;
+       ppc-* | ppcbe-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos | rdos64)
+               basic_machine=x86_64-pc
+               os=-rdos
+               ;;
+       rdos32)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sde)
+               basic_machine=mipsisa32-sde
+               os=-elf
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh5el)
+               basic_machine=sh5le-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       strongarm-* | thumb-*)
+               basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tile*)
+               basic_machine=$basic_machine-unknown
+               os=-linux-gnu
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       xscale-* | xscalee[bl]-*)
+               basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       z80-*-coff)
+               basic_machine=z80-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+       # First match some system type aliases
+       # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -auroraux)
+               os=-auroraux
+               ;;
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* | -plan9* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* | -aros* | -cloudabi* | -sortix* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+             | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* | -cegcc* \
+             | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+             | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+             | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -tpf*)
+               os=-tpf
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -dicos*)
+               os=-dicos
+               ;;
+       -nacl*)
+               ;;
+       -ios)
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       score-*)
+               os=-elf
+               ;;
+       spu-*)
+               os=-elf
+               ;;
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       c8051-*)
+               os=-elf
+               ;;
+       hexagon-*)
+               os=-elf
+               ;;
+       tic54x-*)
+               os=-coff
+               ;;
+       tic55x-*)
+               os=-coff
+               ;;
+       tic6x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mep-*)
+               os=-elf
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -cnk*|-aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.sub.dh-orig b/config.sub.dh-orig
new file mode 100755 (executable)
index 0000000..0432524
--- /dev/null
@@ -0,0 +1,927 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+       echo Configuration name missing. 1>&2
+       echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+       echo "or     $0 ALIAS" 1>&2
+       echo where ALIAS is a recognized configuration type. 1>&2
+       exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+       *local*)
+               echo $1
+               exit 0
+               ;;
+       *)
+       ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  linux-gnu*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple)
+               os=
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \
+               | arme[lb] | pyramid \
+               | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \
+               | alpha | we32k | ns16k | clipper | i370 | sh \
+               | powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \
+               | pdp11 | mips64el | mips64orion | mips64orionel \
+               | sparc | sparclet | sparclite | sparc64)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i[3456]86)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+             | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
+             | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+             | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+             | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* | f301-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-cbm
+               ;;
+       amigados)
+               basic_machine=m68k-cbm
+               os=-amigados
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-cbm
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [ctj]90-cray)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i[3456]86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i[3456]86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i[3456]86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i[3456]86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5)
+               basic_machine=i586-intel
+               ;;
+       pentiumpro | p6)
+               basic_machine=i686-intel
+               ;;
+       pentium-* | p5-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       k5)
+               # We don't have specific support for AMD's K5 yet, so just call it a Pentium
+               basic_machine=i586-amd
+               ;;
+       nexen)
+               # We don't have specific support for Nexgen yet, so just call it a Pentium
+               basic_machine=i586-nexgen
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=rs6000-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       mips)
+               basic_machine=mips-mips
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sparc)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -unixware* | svr4*)
+               os=-sysv4
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -linux-gnu* | -uxpv*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigados
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f301-fujitsu)
+               os=-uxpv
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..bb2d78f
--- /dev/null
+++ b/configure
@@ -0,0 +1,2782 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=thttpd.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+#    configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+#    same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+#    as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:573: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:594: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+  case $nonopt in
+  NONE) target_alias=$host_alias ;;
+  *) target_alias=$nonopt ;;
+  esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:612: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+  case $nonopt in
+  NONE) build_alias=$host_alias ;;
+  *) build_alias=$nonopt ;;
+  esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:638: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:668: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:719: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:751: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 762 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:767: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:793: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:798: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:807: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:826: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+
+V_CCOPT="-O"
+if test "$GCC" = yes ; then
+       echo $ac_n "checking gcc version""... $ac_c" 1>&6
+echo "configure:861: checking gcc version" >&5
+       if eval "test \"`echo '$''{'ac_cv_lbl_gcc_vers'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_lbl_gcc_vers=`$CC -dumpversion 2>&1 | \
+               sed -e 's/\..*//'`
+fi
+
+       echo "$ac_t""$ac_cv_lbl_gcc_vers" 1>&6
+       if test "$ac_cv_lbl_gcc_vers" -gt 1 ; then
+               V_CCOPT="-O2"
+       fi
+fi
+if test -f .devel ; then
+       V_CCOPT="-g $V_CCOPT -ansi -pedantic -U__STRICT_ANSI__ -Wall -Wpointer-arith -Wshadow -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wno-long-long"
+fi
+
+echo $ac_n "checking how to link static binaries""... $ac_c" 1>&6
+echo "configure:879: checking how to link static binaries" >&5
+if eval "test \"`echo '$''{'ac_cv_lbl_static_flag'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_lbl_static_flag=unknown
+    echo 'main() {}' > conftest.c
+    if test "$GCC" != yes ; then
+           trial_flag="-Bstatic"
+           test=`$CC $trial_flag -o conftest conftest.c 2>&1`
+           if test -z "$test" ; then
+                   ac_cv_lbl_static_flag="$trial_flag"
+           fi
+           rm -f conftest
+    fi
+    if test "$ac_cv_lbl_static_flag" = unknown ; then
+           trial_flag="-static"
+           test=`$CC $trial_flag -o conftest conftest.c 2>&1`
+           if test -z "$test" ; then
+                   ac_cv_lbl_static_flag="$trial_flag"
+           fi
+           rm -f conftest
+    fi
+    rm conftest.c
+fi
+
+echo "$ac_t""$ac_cv_lbl_static_flag" 1>&6
+if test "$ac_cv_lbl_static_flag" != unknown ; then
+       V_STATICFLAG="$ac_cv_lbl_static_flag"
+fi
+
+echo $ac_n "checking for __progname""... $ac_c" 1>&6
+echo "configure:910: checking for __progname" >&5
+if eval "test \"`echo '$''{'ac_cv_extern__progname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 915 "configure"
+#include "confdefs.h"
+
+int main() {
+extern char *__progname; 
+       puts(__progname)
+; return 0; }
+EOF
+if { (eval echo configure:923: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_extern__progname=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_extern__progname=no
+fi
+rm -f conftest*
+fi
+
+if test $ac_cv_extern__progname = yes ; then
+       cat >> confdefs.h <<\EOF
+#define HAVE__PROGNAME 1
+EOF
+
+       echo "$ac_t""yes" 1>&6
+else
+       echo "$ac_t""no" 1>&6   
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:946: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 961 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:967: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 978 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:984: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 995 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1001: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+for ac_hdr in fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/devpoll.h sys/event.h osreldate.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1029: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1034 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1039: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1066: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1071 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1080: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1105: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1110 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1118: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1143: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1151 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1162: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1184: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1192 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1203: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+d="/usr/local/v6/lib"
+echo $ac_n "checking for $d""... $ac_c" 1>&6
+echo "configure:1228: checking for $d" >&5
+if test -d $d; then
+       echo "$ac_t""yes (Adding -L$d to LDFLAGS)" 1>&6
+       LDFLAGS="$LDFLAGS -L$d"
+else
+       echo "$ac_t""no" 1>&6
+fi
+
+V_NETLIBS=""
+echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:1238: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1243 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1266: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+# Some OSes (eg. Solaris) place it in libnsl:
+    echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:1285: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname'_' | sed 'y%./+- %__p__%'`
+if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1293 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1304: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lnsl $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+# Some strange OSes (SINIX) have it in libsocket:
+       echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
+echo "configure:1324: checking for gethostbyname in -lsocket" >&5
+ac_lib_var=`echo socket'_'gethostbyname'_' | sed 'y%./+- %__p__%'`
+if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1332 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1343: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lsocket $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+# Unfortunately libsocket sometimes depends on libnsl.
+           # AC_CHECK_LIB's API is essentially broken so the
+           # following ugliness is necessary:
+           echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
+echo "configure:1365: checking for gethostbyname in -lsocket" >&5
+ac_lib_var=`echo socket'_'gethostbyname'_'-lnsl | sed 'y%./+- %__p__%'`
+if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket -lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1373 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1384: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lsocket -lnsl $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6
+echo "configure:1403: checking for gethostbyname in -lresolv" >&5
+ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lresolv  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1411 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1422: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lresolv $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+fi
+
+fi
+
+echo $ac_n "checking for socket""... $ac_c" 1>&6
+echo "configure:1451: checking for socket" >&5
+if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1456 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char socket(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_socket) || defined (__stub___socket)
+choke me
+#else
+socket();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_socket=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_socket=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1497: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1505 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1516: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lsocket $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1535: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket'_'-lnsl | sed 'y%./+- %__p__%'`
+if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket -lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1543 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1554: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lbl_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lsocket -lnsl $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+
+echo $ac_n "checking for main in -linet6""... $ac_c" 1>&6
+echo "configure:1580: checking for main in -linet6" >&5
+ac_lib_var=`echo inet6'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-linet6  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1588 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1595: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo inet6 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-linet6 $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking for crypt""... $ac_c" 1>&6
+echo "configure:1624: checking for crypt" >&5
+if eval "test \"`echo '$''{'ac_cv_func_crypt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1629 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char crypt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char crypt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_crypt) || defined (__stub___crypt)
+choke me
+#else
+crypt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1652: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_crypt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_crypt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'crypt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
+echo "configure:1670: checking for crypt in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrypt  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1678 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char crypt();
+
+int main() {
+crypt()
+; return 0; }
+EOF
+if { (eval echo configure:1689: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lcrypt $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for hstrerror""... $ac_c" 1>&6
+echo "configure:1719: checking for hstrerror" >&5
+if eval "test \"`echo '$''{'ac_cv_func_hstrerror'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1724 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char hstrerror(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char hstrerror();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_hstrerror) || defined (__stub___hstrerror)
+choke me
+#else
+hstrerror();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_hstrerror=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_hstrerror=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'hstrerror`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for hstrerror in -lresolv""... $ac_c" 1>&6
+echo "configure:1765: checking for hstrerror in -lresolv" >&5
+ac_lib_var=`echo resolv'_'hstrerror | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lresolv  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1773 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char hstrerror();
+
+int main() {
+hstrerror()
+; return 0; }
+EOF
+if { (eval echo configure:1784: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  V_NETLIBS="-lresolv $V_NETLIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+for ac_func in strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1810: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1815 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+for ac_func in waitpid vsnprintf daemon setsid setlogin getaddrinfo getnameinfo gai_strerror kqueue sigset atoll
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1867: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1872 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1895: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1923: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1928 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1933: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1962: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1967 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for working mmap""... $ac_c" 1>&6
+echo "configure:2015: checking for working mmap" >&5
+if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_mmap_fixed_mapped=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2023 "configure"
+#include "confdefs.h"
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+   Here is a matrix of mmap possibilities:
+       mmap private not fixed
+       mmap private fixed at somewhere currently unmapped
+       mmap private fixed at somewhere already mapped
+       mmap shared not fixed
+       mmap shared fixed at somewhere currently unmapped
+       mmap shared fixed at somewhere already mapped
+   For private mappings, we should verify that changes cannot be read()
+   back from the file, nor mmap's back from the file at a different
+   address.  (There have been systems where private was not correctly
+   implemented like the infamous i386 svr4.0, and systems where the
+   VM page cache was not coherent with the filesystem buffer cache
+   like early versions of FreeBSD and possibly contemporary NetBSD.)
+   For shared mappings, we should conversely verify that changes get
+   propogated back to all the places they're supposed to be.
+
+   Grep wants private fixed already mapped.
+   The main things grep needs to know about mmap are:
+   * does it exist and is it safe to write into the mmap'd area
+   * how to use it (BSD variants)  */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192  /* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+#ifdef __cplusplus
+extern "C" { void *malloc(unsigned); }
+#else
+char *malloc();
+#endif
+
+int
+main()
+{
+       char *data, *data2, *data3;
+       int i, pagesize;
+       int fd;
+
+       pagesize = getpagesize();
+
+       /*
+        * First, make a file with some known garbage in it.
+        */
+       data = malloc(pagesize);
+       if (!data)
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               *(data + i) = rand();
+       umask(0);
+       fd = creat("conftestmmap", 0600);
+       if (fd < 0)
+               exit(1);
+       if (write(fd, data, pagesize) != pagesize)
+               exit(1);
+       close(fd);
+
+       /*
+        * Next, try to mmap the file at a fixed address which
+        * already has something else allocated at it.  If we can,
+        * also make sure that we see the same garbage.
+        */
+       fd = open("conftestmmap", O_RDWR);
+       if (fd < 0)
+               exit(1);
+       data2 = malloc(2 * pagesize);
+       if (!data2)
+               exit(1);
+       data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1);
+       if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE,
+           MAP_PRIVATE | MAP_FIXED, fd, 0L))
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               if (*(data + i) != *(data2 + i))
+                       exit(1);
+
+       /*
+        * Finally, make sure that changes to the mapped area
+        * do not percolate back to the file as seen by read().
+        * (This is a bug on some variants of i386 svr4.0.)
+        */
+       for (i = 0; i < pagesize; ++i)
+               *(data2 + i) = *(data2 + i) + 1;
+       data3 = malloc(pagesize);
+       if (!data3)
+               exit(1);
+       if (read(fd, data3, pagesize) != pagesize)
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               if (*(data + i) != *(data3 + i))
+                       exit(1);
+       close(fd);
+       unlink("conftestmmap");
+       exit(0);
+}
+
+EOF
+if { (eval echo configure:2163: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_mmap_fixed_mapped=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_MMAP 1
+EOF
+
+fi
+
+
+case "$target_os" in
+solaris*)
+               for ac_func in poll
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2191: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2196 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2219: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+       ;;
+*)
+       for ac_func in select poll
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2248: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2253 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2276: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+       ;;
+esac
+
+echo $ac_n "checking if struct tm has tm_gmtoff member""... $ac_c" 1>&6
+echo "configure:2304: checking if struct tm has tm_gmtoff member" >&5
+    if eval "test \"`echo '$''{'ac_cv_acme_tm_has_tm_gmtoff'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2309 "configure"
+#include "confdefs.h"
+
+#      include <sys/types.h>
+#      include <time.h>
+int main() {
+u_int i = sizeof(((struct tm *)0)->tm_gmtoff)
+; return 0; }
+EOF
+if { (eval echo configure:2318: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_acme_tm_has_tm_gmtoff=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_acme_tm_has_tm_gmtoff=no
+fi
+rm -f conftest*
+fi
+
+    echo "$ac_t""$ac_cv_acme_tm_has_tm_gmtoff" 1>&6
+    if test $ac_cv_acme_tm_has_tm_gmtoff = yes ; then
+           cat >> confdefs.h <<\EOF
+#define HAVE_TM_GMTOFF 1
+EOF
+
+    fi
+echo $ac_n "checking if int64_t exists""... $ac_c" 1>&6
+echo "configure:2338: checking if int64_t exists" >&5
+    if eval "test \"`echo '$''{'ac_cv_acme_int64_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2343 "configure"
+#include "confdefs.h"
+
+#      include <sys/types.h>
+int main() {
+int64_t i64
+; return 0; }
+EOF
+if { (eval echo configure:2351: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_acme_int64_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_acme_int64_t=no
+fi
+rm -f conftest*
+fi
+
+    echo "$ac_t""$ac_cv_acme_int64_t" 1>&6
+    if test $ac_cv_acme_int64_t = yes ; then
+           cat >> confdefs.h <<\EOF
+#define HAVE_INT64T 1
+EOF
+
+    fi
+echo $ac_n "checking if socklen_t exists""... $ac_c" 1>&6
+echo "configure:2371: checking if socklen_t exists" >&5
+    if eval "test \"`echo '$''{'ac_cv_acme_socklen_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2376 "configure"
+#include "confdefs.h"
+
+#      include <sys/types.h>
+#      include <sys/socket.h>
+int main() {
+socklen_t slen
+; return 0; }
+EOF
+if { (eval echo configure:2385: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_acme_socklen_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_acme_socklen_t=no
+fi
+rm -f conftest*
+fi
+
+    echo "$ac_t""$ac_cv_acme_socklen_t" 1>&6
+    if test $ac_cv_acme_socklen_t = yes ; then
+           cat >> confdefs.h <<\EOF
+#define HAVE_SOCKLENT 1
+EOF
+
+    fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:2406: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+       @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:2444: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[    `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile cgi-src/Makefile extras/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@V_CCOPT@%$V_CCOPT%g
+s%@V_STATICFLAG@%$V_STATICFLAG%g
+s%@V_NETLIBS@%$V_NETLIBS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile cgi-src/Makefile extras/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..1209ddc
--- /dev/null
@@ -0,0 +1,138 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(thttpd.c)
+
+AC_CANONICAL_SYSTEM
+
+AC_PROG_CC
+
+V_CCOPT="-O"
+if test "$GCC" = yes ; then
+       AC_MSG_CHECKING(gcc version)
+       AC_CACHE_VAL(ac_cv_lbl_gcc_vers,
+           ac_cv_lbl_gcc_vers=`$CC -dumpversion 2>&1 | \
+               sed -e 's/\..*//'`)
+       AC_MSG_RESULT($ac_cv_lbl_gcc_vers)
+       if test "$ac_cv_lbl_gcc_vers" -gt 1 ; then
+               V_CCOPT="-O2"
+       fi
+fi
+if test -f .devel ; then
+       V_CCOPT="-g $V_CCOPT -ansi -pedantic -U__STRICT_ANSI__ -Wall -Wpointer-arith -Wshadow -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wno-long-long"
+fi
+
+dnl
+dnl maybe this should be a loop
+dnl
+AC_MSG_CHECKING(how to link static binaries)
+AC_CACHE_VAL(ac_cv_lbl_static_flag,
+    ac_cv_lbl_static_flag=unknown
+    echo 'main() {}' > conftest.c
+    if test "$GCC" != yes ; then
+           trial_flag="-Bstatic"
+           test=`$CC $trial_flag -o conftest conftest.c 2>&1`
+           if test -z "$test" ; then
+                   ac_cv_lbl_static_flag="$trial_flag"
+           fi
+           rm -f conftest
+    fi
+    if test "$ac_cv_lbl_static_flag" = unknown ; then
+           trial_flag="-static"
+           test=`$CC $trial_flag -o conftest conftest.c 2>&1`
+           if test -z "$test" ; then
+                   ac_cv_lbl_static_flag="$trial_flag"
+           fi
+           rm -f conftest
+    fi
+    rm conftest.c)
+AC_MSG_RESULT($ac_cv_lbl_static_flag)
+if test "$ac_cv_lbl_static_flag" != unknown ; then
+       V_STATICFLAG="$ac_cv_lbl_static_flag"
+fi
+
+AC_MSG_CHECKING(for __progname)
+AC_CACHE_VAL(ac_cv_extern__progname,
+    AC_TRY_LINK([],
+       [extern char *__progname; 
+       puts(__progname)],
+       ac_cv_extern__progname=yes,
+       ac_cv_extern__progname=no))
+if test $ac_cv_extern__progname = yes ; then
+       AC_DEFINE(HAVE__PROGNAME)
+       AC_MSG_RESULT(yes)
+else
+       AC_MSG_RESULT(no)   
+fi
+
+AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/devpoll.h sys/event.h osreldate.h)
+AC_HEADER_TIME
+AC_HEADER_DIRENT
+
+d="/usr/local/v6/lib"
+AC_MSG_CHECKING(for $d)
+if test -d $d; then
+       AC_MSG_RESULT(yes (Adding -L$d to LDFLAGS))
+       LDFLAGS="$LDFLAGS -L$d"
+else
+       AC_MSG_RESULT(no)
+fi
+
+dnl
+dnl Most operating systems have gethostbyname() in the default searched
+dnl libraries (i.e. libc):
+dnl
+V_NETLIBS=""
+AC_CHECK_FUNC(gethostbyname, ,
+    # Some OSes (eg. Solaris) place it in libnsl:
+    AC_LBL_CHECK_LIB(nsl, gethostbyname,
+       V_NETLIBS="-lnsl $V_NETLIBS", 
+       # Some strange OSes (SINIX) have it in libsocket:
+       AC_LBL_CHECK_LIB(socket, gethostbyname,
+           V_NETLIBS="-lsocket $V_NETLIBS", 
+           # Unfortunately libsocket sometimes depends on libnsl.
+           # AC_CHECK_LIB's API is essentially broken so the
+           # following ugliness is necessary:
+           AC_LBL_CHECK_LIB(socket, gethostbyname,
+               V_NETLIBS="-lsocket -lnsl $V_NETLIBS",
+               AC_CHECK_LIB(resolv, gethostbyname,
+                   V_NETLIBS="-lresolv $V_NETLIBS"),
+               -lnsl))))
+AC_CHECK_FUNC(socket, ,
+    AC_CHECK_LIB(socket, socket,
+       V_NETLIBS="-lsocket $V_NETLIBS",
+       AC_LBL_CHECK_LIB(socket, socket,
+           V_NETLIBS="-lsocket -lnsl $V_NETLIBS", , -lnsl)))
+
+AC_CHECK_LIB(inet6, main)
+
+AC_CHECK_FUNC(crypt, , AC_CHECK_LIB(crypt, crypt))
+AC_CHECK_FUNC(hstrerror, ,
+    AC_CHECK_LIB(resolv, hstrerror, V_NETLIBS="-lresolv $V_NETLIBS"))
+
+AC_REPLACE_FUNCS(strerror)
+AC_CHECK_FUNCS(waitpid vsnprintf daemon setsid setlogin getaddrinfo getnameinfo gai_strerror kqueue sigset atoll)
+AC_FUNC_MMAP
+
+case "$target_os" in
+solaris*)
+       dnl Solaris's select() is a bad wrapper routine.
+       AC_CHECK_FUNCS(poll)
+       ;;
+*)
+       AC_CHECK_FUNCS(select poll)
+       ;;
+esac
+
+AC_ACME_TM_GMTOFF
+AC_ACME_INT64T
+AC_ACME_SOCKLENT
+
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+
+AC_SUBST(DEFS)
+AC_SUBST(V_CCOPT)
+AC_SUBST(V_STATICFLAG)
+AC_SUBST(V_NETLIBS)
+
+AC_OUTPUT(Makefile cgi-src/Makefile extras/Makefile)
diff --git a/contrib/redhat-rpm/thttpd.conf b/contrib/redhat-rpm/thttpd.conf
new file mode 100644 (file)
index 0000000..02fce15
--- /dev/null
@@ -0,0 +1,14 @@
+# This section overrides defaults
+dir=/home/httpd/html
+chroot
+user=httpd# default = nobody
+logfile=/var/log/thttpd.log
+pidfile=/var/run/thttpd.pid
+# This section _documents_ defaults in effect
+# port=80
+# nosymlink# default = !chroot
+# novhost
+# nocgipat
+# nothrottles
+# host=0.0.0.0
+# charset=iso-8859-1
diff --git a/contrib/redhat-rpm/thttpd.init b/contrib/redhat-rpm/thttpd.init
new file mode 100755 (executable)
index 0000000..58e3aba
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+# The following two lines enable chkconfig(1) to manipulate this script
+# chkconfig: 2345 99 01
+# description: control Jef Poskanzer's tiny/turbo/throttling http daemon
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+pidfile=/var/run/thttpd.pid
+pid=`cat $pidfile 2>/dev/null`
+
+if test -n "$pid" && kill -0 $pid 2>/dev/null; then
+       dead=no
+else
+       dead=yes
+fi
+
+die(){
+       echo -n "$*"; echo_failure; echo ''
+       exit 1;
+}
+
+case "$1" in
+ start)        test "$dead" = yes || die thttpd is already running
+       echo -n "Starting thttpd: "
+       daemon /usr/sbin/thttpd -C /etc/thttpd.conf
+       touch /var/lock/subsys/thttpd
+       echo_success;echo ''
+       exit 0
+       ;;
+  stop)        echo -n "Gently shutting down thttpd: "
+       signal=USR1
+       ;;
+  kill)        echo -n "Violently killing thttpd: "
+       signal=INT
+       ;;
+status)        status thttpd; exit $?;;
+restart) $0 stop; sleep 2; exec $0 start;;
+     *)        die "Usage: thttpd {start|stop|restart|status}";;
+esac
+
+test "$dead" = no || die thttpd is not running
+kill -$signal $pid
+sleep 2
+kill -0 $pid 2>/dev/null && die "thttpd[$pid] will not die"
+rm -f /var/lock/subsys/thttpd
+echo_success; echo ''
diff --git a/contrib/redhat-rpm/thttpd.spec b/contrib/redhat-rpm/thttpd.spec
new file mode 100644 (file)
index 0000000..6ee0fee
--- /dev/null
@@ -0,0 +1,154 @@
+Summary: Throttleable lightweight httpd server
+Name: thttpd
+Version: 2.29
+Release: 1
+Group: Networking
+URL: http://www.acme.com/software/thttpd
+Source0: http://www.acme.com/software/thttpd/thttpd-%{PACKAGE_VERSION}.tar.gz
+Copyright: distributable (BSD)
+BuildRoot: /tmp/thttpd-root
+
+%description
+Thttpd is a very compact no-frills httpd serving daemon that can handle
+very high loads.  While lacking many of the advanced features of
+Apachee, thttpd operates without forking and is extremely efficient in
+memory use.  Basic support for cgi scripts, authentication, and ssi is
+provided for.  Advanced features include the ability to throttle traffic.
+
+%prep
+%setup
+
+./configure --prefix=/usr
+
+%build
+make \
+       WEBDIR=/home/httpd/html \
+       BINDIR=/usr/sbin prefix=/usr \
+       CGIBINDIR=/home/httpd/cgi-bin
+
+%install
+
+mkdir -p $RPM_BUILD_ROOT/home/httpd/{cgi-bin,logs}
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
+mkdir -p $RPM_BUILD_ROOT/usr/man/man{1,8}
+mkdir -p $RPM_BUILD_ROOT/usr/sbin
+install  contrib/redhat-rpm/thttpd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/thttpd
+install  contrib/redhat-rpm/thttpd.conf $RPM_BUILD_ROOT/etc/
+make -i prefix=$RPM_BUILD_ROOT/usr install
+
+%pre
+
+grep '^httpd:' /etc/passwd >/dev/null || \
+       /usr/sbin/adduser -r httpd
+
+%post
+/sbin/chkconfig --add thttpd
+
+%preun
+/sbin/chkconfig --del thttpd
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,bin,bin)
+%doc [A-Z]*
+%attr(2755, httpd, httpd) /usr/sbin/makeweb
+/usr/sbin/htpasswd
+/usr/sbin/syslogtocern
+/usr/sbin/thttpd
+%attr(-, httpd, httpd) /home/httpd
+%attr(0755, root, root) /etc/rc.d/init.d/thttpd
+%config /etc/thttpd.conf
+%doc /usr/man/man*/*
+
+%changelog
+
+* Mon Dec 29 2003 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.26
+
+* Sat Dec 20 2003 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.25b
+
+* Mon Oct 27 2003 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.25
+
+* Sat Sep 13 2003 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.24
+
+* Sat May 25 2002 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.23
+
+* Mon Jul 09 2001 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.22
+
+* Thu Apr 26 2001 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.21c
+
+* Mon Apr 23 2001 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.21b
+
+* Mon Oct 02 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.21
+
+* Wed Sep 13 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.20
+
+* Mon Sep 11 2000 Bennett Todd <bet@rahul.net>
+  - added thttpd.conf, took config info out of init script
+  - switched to logging in /var/log, used pidfile
+
+* Thu Jun 15 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.19
+
+* Thu May 18 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.18
+
+* Fri Mar 17 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.17
+
+* Mon Feb 28 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.16
+
+* Thu Feb 03 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.15
+
+* Thu Jan 21 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.14
+
+* Thu Jan  6 2000 Jef Poskanzer <jef@mail.acme.com>
+  - Updated to 2.13
+
+* Mon Jan  3 2000 Bennett Todd <bet@rahul.net>
+  - updated to 2.12, tweaked to move thttpd.init into tarball
+
+* Mon Dec 13 1999 Bennett Todd <bet@mordor.net>
+  - Updated to 2.09
+
+* Fri Dec 10 1999 Bennett Todd <bet@mordor.net>
+  - Updated to 2.08
+
+* Wed Nov 24 1999 Bennett Todd <bet@mordor.net>
+  - updated to 2.06, parameterized Version string in source url
+  - changed to use "make install", simplified %files list
+
+* Wed Nov 10 1999 Bennett Todd <bet@mordor.net>
+  - Version 2.05, reset release to 1
+  - dropped bugfix patch since Jef included that
+  - streamlined install
+
+* Sun Jul 25 1999 Bennett Todd <bet@mordor.net>
+  - Release 4, added mime type swf
+
+* Mon May  3 1999 Bennett Todd <bet@mordor.net>
+  - Release 2, added patch to set cgi-timelimit up to 10 minutes
+    fm default 30 seconds
+
+* Wed Feb 10 1999 Bennett Todd <bet@mordor.net>
+  - based on 2.00-2, bumped to 2.04, reset release back to 1
+  - fixed a couple of broken entries in %install to reference $RPM_BUILD_ROOT
+  - simplified %files to populate /usr/doc/... with just [A-Z]* (TODO had gone
+    away, this simplification makes it liklier to be trivially portable to
+    future releases).
+  - added %doc tags for the man pages
+
diff --git a/debian/.debhelper/thttpd/dbgsym-build-ids b/debian/.debhelper/thttpd/dbgsym-build-ids
new file mode 100644 (file)
index 0000000..3567acc
--- /dev/null
@@ -0,0 +1 @@
+16c41619dbe2621d5592bc2134a67ffe4f585557
diff --git a/debian/.debhelper/thttpd/dbgsym-root/DEBIAN/control b/debian/.debhelper/thttpd/dbgsym-root/DEBIAN/control
new file mode 100644 (file)
index 0000000..c23d09a
--- /dev/null
@@ -0,0 +1,13 @@
+Package: thttpd-dbgsym
+Source: thttpd
+Version: 2.29-1
+Auto-Built-Package: debug-symbols
+Architecture: amd64
+Maintainer: Ralph Ronnquist <ralph.ronnquist@gmail.com>
+Installed-Size: 29
+Depends: thttpd (= 2.29-1)
+Section: debug
+Priority: extra
+Homepage: https://acme.com/software/thttpd/
+Description: Debug symbols for thttpd
+Build-Ids: 16c41619dbe2621d5592bc2134a67ffe4f585557
diff --git a/debian/.debhelper/thttpd/dbgsym-root/DEBIAN/md5sums b/debian/.debhelper/thttpd/dbgsym-root/DEBIAN/md5sums
new file mode 100644 (file)
index 0000000..80d241c
--- /dev/null
@@ -0,0 +1 @@
+5d5b43817d2c8a05ab36b2706e92f2e4  usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug
diff --git a/debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug b/debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug
new file mode 100644 (file)
index 0000000..ee1e8dc
Binary files /dev/null and b/debian/.debhelper/thttpd/dbgsym-root/usr/lib/debug/.build-id/16/c41619dbe2621d5592bc2134a67ffe4f585557.debug differ
diff --git a/debian/.debhelper/thttpd/dbgsym-root/usr/share/doc/thttpd-dbgsym b/debian/.debhelper/thttpd/dbgsym-root/usr/share/doc/thttpd-dbgsym
new file mode 120000 (symlink)
index 0000000..e25805c
--- /dev/null
@@ -0,0 +1 @@
+thttpd
\ No newline at end of file
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644 (file)
index 0000000..f6f5b71
--- /dev/null
@@ -0,0 +1,6 @@
+thttpd for Debian
+----------------
+
+<possible notes regarding this package - if none, delete this file>
+
+ -- Ralph Ronnquist <ralph.ronnquist@gmail.com>  Sat, 07 Jul 2018 17:38:08 +1000
diff --git a/debian/README.source b/debian/README.source
new file mode 100644 (file)
index 0000000..f3a9c85
--- /dev/null
@@ -0,0 +1,10 @@
+thttpd for Debian
+----------------
+
+<this file describes information about the source package, see Debian policy
+manual section 4.14. You WILL either need to modify or delete this file>
+
+
+
+ -- Ralph Ronnquist <ralph.ronnquist@gmail.com>  Sat, 07 Jul 2018 17:38:08 +1000
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..22faeb6
--- /dev/null
@@ -0,0 +1,5 @@
+thttpd (2.29-1) unstable; urgency=medium
+
+  * Initial release (Closes: #nnnn)  <nnnn is the bug number of your ITP>
+
+ -- Ralph Ronnquist <ralph.ronnquist@gmail.com>  Sat, 07 Jul 2018 17:38:08 +1000
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..0b02258
--- /dev/null
@@ -0,0 +1,28 @@
+Source: thttpd
+Section: unknown
+Priority: optional
+Maintainer: Ralph Ronnquist <ralph.ronnquist@gmail.com>
+Build-Depends: debhelper (>= 9), autotools-dev
+Standards-Version: 3.9.8
+Homepage: https://acme.com/software/thttpd/
+#Vcs-Git: https://anonscm.debian.org/collab-maint/thttpd.git
+#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/thttpd.git
+
+Package: thttpd
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: tiny/turbo/throttling HTTP server
+  thttpd is a simple, small, portable, fast, and secure HTTP server.
+ .
+ Simple:
+    It handles only the minimum necessary to implement HTTP/1.1. Well, maybe a little more than the minimum. 
+ Small:
+    See the comparison chart. It also has a very small run-time size, since it does not fork and is very careful about memory allocation. 
+ Portable:
+    It compiles cleanly on most any Unix-like OS, specifically including FreeBSD, SunOS 4, Solaris 2, BSD/OS, Linux, OSF. 
+ Fast:
+    In typical use it's about as fast as the best full-featured servers (Apache, NCSA, Netscape). Under extreme load it's much faster. 
+ Secure:
+    It goes to great lengths to protect the web server machine against attacks and breakins from other sites. 
+ .
+ It also has one extremely useful feature (URL-traffic-based throttling) that no other server currently has. Plus, it supports IPv6 out of the box, no patching required
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..e828fd4
--- /dev/null
@@ -0,0 +1,34 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: thttpd
+Source: <url://example.com>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+           <years> <likewise for another author>
+License: GPL-3.0+
+
+Files: debian/*
+Copyright: 2018 Ralph Ronnquist <ralph.ronnquist@gmail.com>
+License: GPL-3.0+
+
+License: GPL-3.0+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+# Please avoid picking licenses with terms that are more restrictive than the
+# packaged work, as it may make Debian's contributions unacceptable upstream.
diff --git a/debian/debhelper-build-stamp b/debian/debhelper-build-stamp
new file mode 100644 (file)
index 0000000..c2754a9
--- /dev/null
@@ -0,0 +1 @@
+thttpd
diff --git a/debian/files b/debian/files
new file mode 100644 (file)
index 0000000..22543b2
--- /dev/null
@@ -0,0 +1,3 @@
+thttpd-dbgsym_2.29-1_amd64.deb debug extra
+thttpd_2.29-1_amd64.buildinfo unknown optional
+thttpd_2.29-1_amd64.deb unknown optional
diff --git a/debian/manpage.1.ex b/debian/manpage.1.ex
new file mode 100644 (file)
index 0000000..3b50623
--- /dev/null
@@ -0,0 +1,56 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" (C) Copyright 2018 Ralph Ronnquist <ralph.ronnquist@gmail.com>,
+.\"
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH Thttpd SECTION "July  7 2018"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+thttpd \- program to do something
+.SH SYNOPSIS
+.B thttpd
+.RI [ options ] " files" ...
+.br
+.B bar
+.RI [ options ] " files" ...
+.SH DESCRIPTION
+This manual page documents briefly the
+.B thttpd
+and
+.B bar
+commands.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+\fBthttpd\fP is a program that...
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+A summary of options is included below.
+For a complete description, see the Info files.
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-v, \-\-version
+Show version of program.
+.SH SEE ALSO
+.BR bar (1),
+.BR baz (1).
+.br
+The programs are documented fully by
+.IR "The Rise and Fall of a Fooish Bar" ,
+available via the Info system.
diff --git a/debian/manpage.sgml.ex b/debian/manpage.sgml.ex
new file mode 100644 (file)
index 0000000..5b05496
--- /dev/null
@@ -0,0 +1,154 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+
+<!-- Process this file with docbook-to-man to generate an nroff manual
+     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view
+     the manual page with: `docbook-to-man manpage.sgml | nroff -man |
+     less'.  A typical entry in a Makefile or Makefile.am is:
+
+manpage.1: manpage.sgml
+       docbook-to-man $< > $@
+
+
+       The docbook-to-man binary is found in the docbook-to-man package.
+       Please remember that if you create the nroff version in one of the
+       debian/rules file targets (such as build), you will need to include
+       docbook-to-man in your Build-Depends control field.
+
+  -->
+
+  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+  <!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
+  <!ENTITY dhsurname   "<surname>SURNAME</surname>">
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY dhdate      "<date>July  7 2018</date>">
+  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+       allowed: see man(7), man(1). -->
+  <!ENTITY dhsection   "<manvolnum>SECTION</manvolnum>">
+  <!ENTITY dhemail     "<email>ralph.ronnquist@gmail.com</email>">
+  <!ENTITY dhusername  "Ralph Ronnquist">
+  <!ENTITY dhucpackage "<refentrytitle>Thttpd</refentrytitle>">
+  <!ENTITY dhpackage   "thttpd">
+
+  <!ENTITY debian      "<productname>Debian</productname>">
+  <!ENTITY gnu         "<acronym>GNU</acronym>">
+  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
+]>
+
+<refentry>
+  <refentryinfo>
+    <address>
+      &dhemail;
+    </address>
+    <author>
+      &dhfirstname;
+      &dhsurname;
+    </author>
+    <copyright>
+      <year>2003</year>
+      <holder>&dhusername;</holder>
+    </copyright>
+    &dhdate;
+  </refentryinfo>
+  <refmeta>
+    &dhucpackage;
+
+    &dhsection;
+  </refmeta>
+  <refnamediv>
+    <refname>&dhpackage;</refname>
+
+    <refpurpose>program to do something</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&dhpackage;</command>
+
+      <arg><option>-e <replaceable>this</replaceable></option></arg>
+
+      <arg><option>--example <replaceable>that</replaceable></option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para>This manual page documents briefly the
+      <command>&dhpackage;</command> and <command>bar</command>
+      commands.</para>
+
+    <para>This manual page was written for the &debian; distribution
+      because the original program does not have a manual page.
+      Instead, it has documentation in the &gnu;
+      <application>Info</application> format; see below.</para>
+
+    <para><command>&dhpackage;</command> is a program that...</para>
+
+  </refsect1>
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>These programs follow the usual &gnu; command line syntax,
+      with long options starting with two dashes (`-').  A summary of
+      options is included below.  For a complete description, see the
+      <application>Info</application> files.</para>
+
+    <variablelist>
+      <varlistentry>
+        <term><option>-h</option>
+          <option>--help</option>
+        </term>
+        <listitem>
+          <para>Show summary of options.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>-v</option>
+          <option>--version</option>
+        </term>
+        <listitem>
+          <para>Show version of program.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para>bar (1), baz (1).</para>
+
+    <para>The programs are documented fully by <citetitle>The Rise and
+      Fall of a Fooish Bar</citetitle> available via the
+      <application>Info</application> system.</para>
+  </refsect1>
+  <refsect1>
+    <title>AUTHOR</title>
+
+    <para>This manual page was written by &dhusername; &dhemail; for
+      the &debian; system (and may be used by others).  Permission is
+      granted to copy, distribute and/or modify this document under
+      the terms of the &gnu; General Public License, Version 2 any
+      later version published by the Free Software Foundation.
+    </para>
+    <para>
+      On Debian systems, the complete text of the GNU General Public
+      License can be found in /usr/share/common-licenses/GPL.
+    </para>
+
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/debian/manpage.xml.ex b/debian/manpage.xml.ex
new file mode 100644 (file)
index 0000000..31c9a34
--- /dev/null
@@ -0,0 +1,291 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+
+<!--
+
+`xsltproc -''-nonet \
+          -''-param man.charmap.use.subset "0" \
+          -''-param make.year.ranges "1" \
+          -''-param make.single.year.ranges "1" \
+          /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl \
+          manpage.xml'
+
+A manual page <package>.<section> will be generated. You may view the
+manual page with: nroff -man <package>.<section> | less'. A typical entry
+in a Makefile or Makefile.am is:
+
+DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl
+XP     = xsltproc -''-nonet -''-param man.charmap.use.subset "0"
+
+manpage.1: manpage.xml
+        $(XP) $(DB2MAN) $<
+
+The xsltproc binary is found in the xsltproc package. The XSL files are in
+docbook-xsl. A description of the parameters you can use can be found in the
+docbook-xsl-doc-* packages. Please remember that if you create the nroff
+version in one of the debian/rules file targets (such as build), you will need
+to include xsltproc and docbook-xsl in your Build-Depends control field.
+Alternatively use the xmlto command/package. That will also automatically
+pull in xsltproc and docbook-xsl.
+
+Notes for using docbook2x: docbook2x-man does not automatically create the
+AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as
+<refsect1> ... </refsect1>.
+
+To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections
+read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be
+found in the docbook-xsl-doc-html package.
+
+Validation can be done using: `xmllint -''-noout -''-valid manpage.xml`
+
+General documentation about man-pages and man-page-formatting:
+man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
+
+-->
+
+  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+  <!ENTITY dhfirstname "FIRSTNAME">
+  <!ENTITY dhsurname   "SURNAME">
+  <!-- dhusername could also be set to "&dhfirstname; &dhsurname;". -->
+  <!ENTITY dhusername  "Ralph Ronnquist">
+  <!ENTITY dhemail     "ralph.ronnquist@gmail.com">
+  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+       allowed: see man(7), man(1) and
+       http://www.tldp.org/HOWTO/Man-Page/q2.html. -->
+  <!ENTITY dhsection   "SECTION">
+  <!-- TITLE should be something like "User commands" or similar (see
+       http://www.tldp.org/HOWTO/Man-Page/q2.html). -->
+  <!ENTITY dhtitle     "thttpd User Manual">
+  <!ENTITY dhucpackage "Thttpd">
+  <!ENTITY dhpackage   "thttpd">
+]>
+
+<refentry>
+  <refentryinfo>
+    <title>&dhtitle;</title>
+    <productname>&dhpackage;</productname>
+    <authorgroup>
+      <author>
+       <firstname>&dhfirstname;</firstname>
+        <surname>&dhsurname;</surname>
+        <contrib>Wrote this manpage for the Debian system.</contrib>
+        <address>
+          <email>&dhemail;</email>
+        </address>
+      </author>
+    </authorgroup>
+    <copyright>
+      <year>2007</year>
+      <holder>&dhusername;</holder>
+    </copyright>
+    <legalnotice>
+      <para>This manual page was written for the Debian system
+        (and may be used by others).</para>
+      <para>Permission is granted to copy, distribute and/or modify this
+        document under the terms of the GNU General Public License,
+        Version 2 or (at your option) any later version published by
+        the Free Software Foundation.</para>
+      <para>On Debian systems, the complete text of the GNU General Public
+        License can be found in
+        <filename>/usr/share/common-licenses/GPL</filename>.</para>
+    </legalnotice>
+  </refentryinfo>
+  <refmeta>
+    <refentrytitle>&dhucpackage;</refentrytitle>
+    <manvolnum>&dhsection;</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>&dhpackage;</refname>
+    <refpurpose>program to do something</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&dhpackage;</command>
+      <!-- These are several examples, how syntaxes could look -->
+      <arg choice="plain"><option>-e <replaceable>this</replaceable></option></arg>
+      <arg choice="opt"><option>--example=<parameter>that</parameter></option></arg>
+      <arg choice="opt">
+        <group choice="req">
+          <arg choice="plain"><option>-e</option></arg>
+          <arg choice="plain"><option>--example</option></arg>
+        </group>
+        <replaceable class="option">this</replaceable>
+      </arg>
+      <arg choice="opt">
+        <group choice="req">
+          <arg choice="plain"><option>-e</option></arg>
+          <arg choice="plain"><option>--example</option></arg>
+        </group>
+        <group choice="req">
+          <arg choice="plain"><replaceable>this</replaceable></arg>
+          <arg choice="plain"><replaceable>that</replaceable></arg>
+        </group>
+      </arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>&dhpackage;</command>
+      <!-- Normally the help and version options make the programs stop
+           right after outputting the requested information. -->
+      <group choice="opt">
+        <arg choice="plain">
+          <group choice="req">
+            <arg choice="plain"><option>-h</option></arg>
+            <arg choice="plain"><option>--help</option></arg>
+          </group>
+        </arg>
+        <arg choice="plain">
+          <group choice="req">
+            <arg choice="plain"><option>-v</option></arg>
+            <arg choice="plain"><option>--version</option></arg>
+          </group>
+        </arg>
+      </group>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1 id="description">
+    <title>DESCRIPTION</title>
+    <para>This manual page documents briefly the
+      <command>&dhpackage;</command> and <command>bar</command>
+      commands.</para>
+    <para>This manual page was written for the Debian distribution
+      because the original program does not have a manual page.
+      Instead, it has documentation in the GNU <citerefentry>
+        <refentrytitle>info</refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry> format; see below.</para>
+    <para><command>&dhpackage;</command> is a program that...</para>
+  </refsect1>
+  <refsect1 id="options">
+    <title>OPTIONS</title>
+    <para>The program follows the usual GNU command line syntax,
+      with long options starting with two dashes (`-').  A summary of
+      options is included below.  For a complete description, see the
+      <citerefentry>
+        <refentrytitle>info</refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry> files.</para>
+    <variablelist>
+      <!-- Use the variablelist.term.separator and the
+           variablelist.term.break.after parameters to
+           control the term elements. -->
+      <varlistentry>
+        <term><option>-e <replaceable>this</replaceable></option></term>
+        <term><option>--example=<replaceable>that</replaceable></option></term>
+        <listitem>
+          <para>Does this and that.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>-h</option></term>
+        <term><option>--help</option></term>
+        <listitem>
+          <para>Show summary of options.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>-v</option></term>
+        <term><option>--version</option></term>
+        <listitem>
+          <para>Show version of program.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1 id="files">
+    <title>FILES</title>
+    <variablelist>
+      <varlistentry>
+        <term><filename>/etc/foo.conf</filename></term>
+        <listitem>
+          <para>The system-wide configuration file to control the
+            behaviour of <application>&dhpackage;</application>. See
+            <citerefentry>
+              <refentrytitle>foo.conf</refentrytitle>
+              <manvolnum>5</manvolnum>
+            </citerefentry> for further details.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><filename>${HOME}/.foo.conf</filename></term>
+        <listitem>
+          <para>The per-user configuration file to control the
+             behaviour of <application>&dhpackage;</application>. See
+             <citerefentry>
+               <refentrytitle>foo.conf</refentrytitle>
+               <manvolnum>5</manvolnum>
+             </citerefentry> for further details.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1 id="environment">
+    <title>ENVIRONMENT</title>
+    <variablelist>
+      <varlistentry>
+        <term><envar>FOO_CONF</envar></term>
+        <listitem>
+          <para>If used, the defined file is used as configuration
+            file (see also <xref linkend="files"/>).</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1 id="diagnostics">
+    <title>DIAGNOSTICS</title>
+    <para>The following diagnostics may be issued
+      on <filename class="devicefile">stderr</filename>:</para>
+    <variablelist>
+      <varlistentry>
+        <term><errortext>Bad configuration file. Exiting.</errortext></term>
+        <listitem>
+          <para>The configuration file seems to contain a broken configuration
+            line. Use the <option>--verbose</option> option, to get more info.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+    <para><command>&dhpackage;</command> provides some return codes, that can
+      be used in scripts:</para>
+    <segmentedlist>
+      <segtitle>Code</segtitle>
+      <segtitle>Diagnostic</segtitle>
+      <seglistitem>
+        <seg><errorcode>0</errorcode></seg>
+        <seg>Program exited successfully.</seg>
+      </seglistitem>
+      <seglistitem>
+        <seg><errorcode>1</errorcode></seg>
+        <seg>The configuration file seems to be broken.</seg>
+      </seglistitem>
+    </segmentedlist>
+  </refsect1>
+  <refsect1 id="bugs">
+    <!-- Or use this section to tell about upstream BTS. -->
+    <title>BUGS</title>
+    <para>The program is currently limited to only work
+      with the <package>foobar</package> library.</para>
+    <para>The upstreams <acronym>BTS</acronym> can be found
+      at <ulink url="http://bugzilla.foo.tld"/>.</para>
+  </refsect1>
+  <refsect1 id="see_also">
+    <title>SEE ALSO</title>
+    <!-- In alpabetical order. -->
+    <para><citerefentry>
+        <refentrytitle>bar</refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>baz</refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>foo.conf</refentrytitle>
+        <manvolnum>5</manvolnum>
+      </citerefentry></para>
+    <para>The programs are documented fully by <citetitle>The Rise and
+      Fall of a Fooish Bar</citetitle> available via the <citerefentry>
+        <refentrytitle>info</refentrytitle>
+        <manvolnum>1</manvolnum>
+      </citerefentry> system.</para>
+  </refsect1>
+</refentry>
+
diff --git a/debian/menu.ex b/debian/menu.ex
new file mode 100644 (file)
index 0000000..7764b3c
--- /dev/null
@@ -0,0 +1,2 @@
+?package(thttpd):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\
+  title="thttpd" command="/usr/bin/thttpd"
diff --git a/debian/postinst.ex b/debian/postinst.ex
new file mode 100644 (file)
index 0000000..99affc5
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+# postinst script for thttpd
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see https://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    configure)
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/postrm.ex b/debian/postrm.ex
new file mode 100644 (file)
index 0000000..7d6523a
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+# postrm script for thttpd
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postrm> `remove'
+#        * <postrm> `purge'
+#        * <old-postrm> `upgrade' <new-version>
+#        * <new-postrm> `failed-upgrade' <old-version>
+#        * <new-postrm> `abort-install'
+#        * <new-postrm> `abort-install' <old-version>
+#        * <new-postrm> `abort-upgrade' <old-version>
+#        * <disappearer's-postrm> `disappear' <overwriter>
+#          <overwriter-version>
+# for details, see https://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+    ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/preinst.ex b/debian/preinst.ex
new file mode 100644 (file)
index 0000000..c22c9f8
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+# preinst script for thttpd
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <new-preinst> `install'
+#        * <new-preinst> `install' <old-version>
+#        * <new-preinst> `upgrade' <old-version>
+#        * <old-preinst> `abort-upgrade' <new-version>
+# for details, see https://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    install|upgrade)
+    ;;
+
+    abort-upgrade)
+    ;;
+
+    *)
+        echo "preinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/prerm.ex b/debian/prerm.ex
new file mode 100644 (file)
index 0000000..8f1270d
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+# prerm script for thttpd
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <prerm> `remove'
+#        * <old-prerm> `upgrade' <new-version>
+#        * <new-prerm> `failed-upgrade' <old-version>
+#        * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
+#        * <deconfigured's-prerm> `deconfigure' `in-favour'
+#          <package-being-installed> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see https://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    remove|upgrade|deconfigure)
+    ;;
+
+    failed-upgrade)
+    ;;
+
+    *)
+        echo "prerm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..58855ef
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+export DH_VERBOSE = 1
+
+# see FEATURE AREAS in dpkg-buildflags(1)
+#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# see ENVIRONMENT in dpkg-buildflags(1)
+# package maintainers to append CFLAGS
+#export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
+# package maintainers to append LDFLAGS
+#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
+
+%:
+       dh $@ --with autotools_dev --without systemd
+
+# dh_make generated override targets
+# This is example for Cmake (See https://bugs.debian.org/641051 )
+override_dh_auto_configure:
+       dh_auto_configure -- --prefix=/usr/local --mandir=/usr/local/man
+
+override_dh_usrlocal:
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/thttpd-docs.docs b/debian/thttpd-docs.docs
new file mode 100644 (file)
index 0000000..7319041
--- /dev/null
@@ -0,0 +1,2 @@
+README.source
+README.Debian
diff --git a/debian/thttpd.cron.d.ex b/debian/thttpd.cron.d.ex
new file mode 100644 (file)
index 0000000..7673773
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Regular cron jobs for the thttpd package
+#
+0 4    * * *   root    [ -x /usr/bin/thttpd_maintenance ] && /usr/bin/thttpd_maintenance
diff --git a/debian/thttpd.debhelper.log b/debian/thttpd.debhelper.log
new file mode 100644 (file)
index 0000000..6153a33
--- /dev/null
@@ -0,0 +1,23 @@
+dh_update_autotools_config
+dh_autotools-dev_updateconfig
+override_dh_auto_configure dh_auto_configure
+dh_auto_configure
+dh_auto_build
+dh_auto_test
+dh_prep
+dh_auto_install
+dh_installdocs
+dh_installchangelogs
+dh_perl
+dh_link
+dh_strip_nondeterminism
+dh_compress
+dh_fixperms
+dh_strip
+dh_makeshlibs
+dh_shlibdeps
+dh_installdeb
+dh_gencontrol
+dh_md5sums
+dh_builddeb
+dh_builddeb
diff --git a/debian/thttpd.default.ex b/debian/thttpd.default.ex
new file mode 100644 (file)
index 0000000..0e50d36
--- /dev/null
@@ -0,0 +1,10 @@
+# Defaults for thttpd initscript
+# sourced by /etc/init.d/thttpd
+# installed at /etc/default/thttpd by the maintainer scripts
+
+#
+# This is a POSIX shell fragment
+#
+
+# Additional options that are passed to the Daemon.
+DAEMON_OPTS=""
diff --git a/debian/thttpd.doc-base.EX b/debian/thttpd.doc-base.EX
new file mode 100644 (file)
index 0000000..d7c7df9
--- /dev/null
@@ -0,0 +1,20 @@
+Document: thttpd
+Title: Debian thttpd Manual
+Author: <insert document author here>
+Abstract: This manual describes what thttpd is
+ and how it can be used to
+ manage online manuals on Debian systems.
+Section: unknown
+
+Format: debiandoc-sgml
+Files: /usr/share/doc/thttpd/thttpd.sgml.gz
+
+Format: postscript
+Files: /usr/share/doc/thttpd/thttpd.ps.gz
+
+Format: text
+Files: /usr/share/doc/thttpd/thttpd.text.gz
+
+Format: HTML
+Index: /usr/share/doc/thttpd/html/index.html
+Files: /usr/share/doc/thttpd/html/*.html
diff --git a/debian/thttpd.substvars b/debian/thttpd.substvars
new file mode 100644 (file)
index 0000000..4881eb6
--- /dev/null
@@ -0,0 +1,3 @@
+shlibs:Depends=libc6 (>= 2.7)
+misc:Depends=
+misc:Pre-Depends=
diff --git a/debian/thttpd/DEBIAN/control b/debian/thttpd/DEBIAN/control
new file mode 100644 (file)
index 0000000..73a743b
--- /dev/null
@@ -0,0 +1,24 @@
+Package: thttpd
+Version: 2.29-1
+Architecture: amd64
+Maintainer: Ralph Ronnquist <ralph.ronnquist@gmail.com>
+Installed-Size: 140
+Depends: libc6 (>= 2.7)
+Section: unknown
+Priority: optional
+Homepage: https://acme.com/software/thttpd/
+Description: tiny/turbo/throttling HTTP server
+  thttpd is a simple, small, portable, fast, and secure HTTP server.
+ .
+ Simple:
+    It handles only the minimum necessary to implement HTTP/1.1. Well, maybe a little more than the minimum.
+ Small:
+    See the comparison chart. It also has a very small run-time size, since it does not fork and is very careful about memory allocation.
+ Portable:
+    It compiles cleanly on most any Unix-like OS, specifically including FreeBSD, SunOS 4, Solaris 2, BSD/OS, Linux, OSF.
+ Fast:
+    In typical use it's about as fast as the best full-featured servers (Apache, NCSA, Netscape). Under extreme load it's much faster.
+ Secure:
+    It goes to great lengths to protect the web server machine against attacks and breakins from other sites.
+ .
+ It also has one extremely useful feature (URL-traffic-based throttling) that no other server currently has. Plus, it supports IPv6 out of the box, no patching required
diff --git a/debian/thttpd/DEBIAN/md5sums b/debian/thttpd/DEBIAN/md5sums
new file mode 100644 (file)
index 0000000..a06a71e
--- /dev/null
@@ -0,0 +1,5 @@
+a26b763da2e1d7b8a43ff034891ad109  usr/local/man/man8/thttpd.8
+59e42258ea3cc0f440729feba8bf7d73  usr/local/sbin/thttpd
+a4c701db3345a7c9a7c6deb32338e915  usr/share/doc/thttpd/README.Debian
+a578191a808074968cb7b02afac0c55f  usr/share/doc/thttpd/changelog.Debian.gz
+88dda395d0decd5e5a07521e4ca02be3  usr/share/doc/thttpd/copyright
diff --git a/debian/thttpd/usr/local/man/man8/thttpd.8 b/debian/thttpd/usr/local/man/man8/thttpd.8
new file mode 100644 (file)
index 0000000..040f74c
--- /dev/null
@@ -0,0 +1,596 @@
+.TH thttpd 8 "29 February 2000"
+.SH NAME
+thttpd - tiny/turbo/throttling HTTP server
+.SH SYNOPSIS
+.B thttpd
+.RB [ -C
+.IR configfile ]
+.RB [ -p
+.IR port ]
+.RB [ -d
+.IR dir ]
+.RB [ -dd
+.IR data_dir ]
+.RB [ -r | -nor ]
+.RB [ -s | -nos ]
+.RB [ -v | -nov ]
+.RB [ -g | -nog ]
+.RB [ -u
+.IR user ]
+.RB [ -c
+.IR cgipat ]
+.RB [ -t
+.IR throttles ]
+.RB [ -h
+.IR host ]
+.RB [ -l
+.IR logfile ]
+.RB [ -i
+.IR pidfile ]
+.RB [ -T
+.IR charset ]
+.RB [ -P
+.IR P3P ]
+.RB [ -M
+.IR maxage ]
+.RB [ -V ]
+.RB [ -D ]
+.SH DESCRIPTION
+.PP
+.I thttpd
+is a simple, small, fast, and secure HTTP server.
+It doesn't have a lot of special features, but it suffices for most uses of
+the web, it's about as fast as the best full-featured servers (Apache, NCSA,
+Netscape),
+and it has one extremely useful feature (URL-traffic-based throttling)
+that no other server currently has.
+.SH OPTIONS
+.TP
+.B -C
+Specifies a config-file to read.
+All options can be set either by command-line flags or in the config file.
+See below for details.
+.TP
+.B -p
+Specifies an alternate port number to listen on.
+The default is 80.
+The config-file option name for this flag is "port",
+and the config.h option is DEFAULT_PORT.
+.TP
+.B -d
+Specifies a directory to chdir() to at startup.
+This is merely a convenience - you could just as easily
+do a cd in the shell script that invokes the program.
+The config-file option name for this flag is "dir",
+and the config.h options are WEBDIR, USE_USER_DIR.
+.TP
+.B -r
+Do a chroot() at initialization time, restricting file access
+to the program's current directory.
+If -r is the compiled-in default, then -nor disables it.
+See below for details.
+The config-file option names for this flag are "chroot" and "nochroot",
+and the config.h option is ALWAYS_CHROOT.
+.TP
+.B -dd
+Specifies a directory to chdir() to after chrooting.
+If you're not chrooting, you might as well do a single chdir() with
+the -d flag.
+If you are chrooting, this lets you put the web files in a subdirectory
+of the chroot tree, instead of in the top level mixed in with the
+chroot files.
+The config-file option name for this flag is "data_dir".
+.TP
+.B -nos
+Don't do explicit symbolic link checking.
+Normally, thttpd explicitly expands any symbolic links in filenames,
+to check that the resulting path stays within the original document tree.
+If you want to turn off this check and save some CPU time, you can use
+the -nos flag, however this is not recommended.
+Note, though, that if you are using the chroot option, the symlink
+checking is unnecessary and is turned off, so the safe way to save
+those CPU cycles is to use chroot.
+The config-file option names for this flag are "symlinkcheck" and "nosymlinkcheck".
+.TP
+.B -v
+Do el-cheapo virtual hosting.
+If -v is the compiled-in default, then -nov disables it.
+See below for details.
+The config-file option names for this flag are "vhost" and "novhost",
+and the config.h option is ALWAYS_VHOST.
+.TP
+.B -g
+Use a global passwd file.
+This means that every file in the entire document tree is protected by
+the single .htpasswd file at the top of the tree.
+Otherwise the semantics of the .htpasswd file are the same.
+If this option is set but there is no .htpasswd file in
+the top-level directory, then thttpd proceeds as if the option was
+not set - first looking for a local .htpasswd file, and if that doesn't
+exist either then serving the file without any password.
+If -g is the compiled-in default, then -nog disables it.
+The config-file option names for this flag are "globalpasswd" and
+"noglobalpasswd",
+and the config.h option is ALWAYS_GLOBAL_PASSWD.
+.TP
+.B -u
+Specifies what user to switch to after initialization when started as root.
+The default is "nobody".
+The config-file option name for this flag is "user",
+and the config.h option is DEFAULT_USER.
+.TP
+.B -c
+Specifies a wildcard pattern for CGI programs, for instance "**.cgi"
+or "/cgi-bin/*".
+See below for details.
+The config-file option name for this flag is "cgipat",
+and the config.h option is CGI_PATTERN.
+.TP
+.B -t
+Specifies a file of throttle settings.
+See below for details.
+The config-file option name for this flag is "throttles".
+.TP
+.B -h
+Specifies a hostname to bind to, for multihoming.
+The default is to bind to all hostnames supported on the local machine.
+See below for details.
+The config-file option name for this flag is "host",
+and the config.h option is SERVER_NAME.
+.TP
+.B -l
+Specifies a file for logging.
+If no -l argument is specified, thttpd logs via syslog().
+If "-l /dev/null" is specified, thttpd doesn't log at all.
+The config-file option name for this flag is "logfile".
+.TP
+.B -i
+Specifies a file to write the process-id to.
+If no file is specified, no process-id is written.
+You can use this file to send signals to thttpd.
+See below for details.
+The config-file option name for this flag is "pidfile".
+.TP
+.B -T
+Specifies the character set to use with text MIME types.
+The default is UTF-8.
+The config-file option name for this flag is "charset",
+and the config.h option is DEFAULT_CHARSET.
+.TP
+.B -P
+Specifies a P3P server privacy header to be returned with all responses.
+See http://www.w3.org/P3P/ for details.
+Thttpd doesn't do anything at all with the string except put it in the
+P3P: response header.
+The config-file option name for this flag is "p3p".
+.TP
+.B -M
+Specifies the number of seconds to be used in a "Cache-Control: max-age"
+header to be returned with all responses.
+An equivalent "Expires" header is also generated.
+The default is no Cache-Control or Expires headers,
+which is just fine for most sites.
+The config-file option name for this flag is "max_age".
+.TP
+.B -V
+Shows the current version info.
+.TP
+.B -D
+This was originally just a debugging flag, however it's worth mentioning
+because one of the things it does is prevent thttpd from making itself
+a background daemon.
+Instead it runs in the foreground like a regular program.
+This is necessary when you want to run thttpd wrapped in a little shell
+script that restarts it if it exits.
+.SH "CONFIG-FILE"
+.PP
+All the command-line options can also be set in a config file.
+One advantage of using a config file is that the file can be changed,
+and thttpd will pick up the changes with a restart.
+.PP
+The syntax of the config file is simple, a series of "option" or
+"option=value" separated by whitespace.
+The option names are listed above with their corresponding command-line flags.
+.SH "CHROOT"
+.PP
+chroot() is a system call that restricts the program's view
+of the filesystem to the current directory and directories
+below it.
+It becomes impossible for remote users to access any file
+outside of the initial directory.
+The restriction is inherited by child processes, so CGI programs get it too.
+This is a very strong security measure, and is recommended.
+The only downside is that only root can call chroot(), so this means
+the program must be started as root.
+However, the last thing it does during initialization is to
+give up root access by becoming another user, so this is safe.
+.PP
+The program can also be compile-time configured to always
+do a chroot(), without needing the -r flag.
+.PP
+Note that with some other web servers, such as NCSA httpd, setting
+up a directory tree for use with chroot() is complicated, involving
+creating a bunch of special directories and copying in various files.
+With thttpd it's a lot easier, all you have to do is make sure
+any shells, utilities, and config files used by your CGI programs and
+scripts are available.
+If you have CGI disabled, or if you make a policy that all CGI programs
+must be written in a compiled language such as C and statically linked,
+then you probably don't have to do any setup at all.
+.PP
+However, one thing you should do is tell syslogd about the chroot tree,
+so that thttpd can still generate syslog messages.
+Check your system's syslodg man page for how to do this.
+In FreeBSD you would put something like this in /etc/rc.conf:
+.nf
+    syslogd_flags="-l /usr/local/www/data/dev/log"
+.fi
+Substitute in your own chroot tree's pathname, of course.
+Don't worry about creating the log socket, syslogd wants to do that itself.
+(You may need to create the dev directory.)
+In Linux the flag is -a instead of -l, and there may be other differences.
+.PP
+Relevant config.h option: ALWAYS_CHROOT.
+.SH "CGI"
+.PP
+thttpd supports the CGI 1.1 spec.
+.PP
+In order for a CGI program to be run, its name must match the pattern
+specified either at compile time or on the command line with the -c flag.
+This is a simple shell-style filename pattern.
+You can use * to match any string not including a slash,
+or ** to match any string including slashes,
+or ? to match any single character.
+You can also use multiple such patterns separated by |.
+The patterns get checked against the filename
+part of the incoming URL.
+Don't forget to quote any wildcard characters so that the shell doesn't
+mess with them.
+.PP
+Restricting CGI programs to a single directory lets the site administrator
+review them for security holes, and is strongly recommended.
+If there are individual users that you trust, you can enable their
+directories too.
+.PP
+If no CGI pattern is specified, neither here nor at compile time,
+then CGI programs cannot be run at all.
+If you want to disable CGI as a security measure, that's how you do it, just
+comment out the patterns in the config file and don't run with the -c flag.
+.PP
+Note: the current working directory when a CGI program gets run is
+the directory that the CGI program lives in.
+This isn't in the CGI 1.1 spec, but it's what most other HTTP servers do.
+.PP
+Relevant config.h options: CGI_PATTERN, CGI_TIMELIMIT, CGI_NICE, CGI_PATH, CGI_LD_LIBRARY_PATH, CGIBINDIR.
+.SH "BASIC AUTHENTICATION"
+.PP
+Basic Authentication is available as an option at compile time.
+If enabled, it uses a password file in the directory to be protected,
+called .htpasswd by default.
+This file is formatted as the familiar colon-separated
+username/encrypted-password pair, records delimited by newlines.
+The protection does not carry over to subdirectories.
+The utility program htpasswd(1) is included to help create and
+modify .htpasswd files.
+.PP
+Relevant config.h option: AUTH_FILE
+.SH "THROTTLING"
+.PP
+The throttle file lets you set maximum byte rates on URLs or URL groups.
+You can optionally set a minimum rate too.
+The format of the throttle file is very simple.
+A # starts a comment, and the rest of the line is ignored.
+Blank lines are ignored.
+The rest of the lines should consist of a pattern, whitespace, and a number.
+The pattern is a simple shell-style filename pattern, using ?/**/*, or
+multiple such patterns separated by |.
+.PP
+The numbers in the file are byte rates, specified in units of bytes per second.
+For comparison, a v.90 modem gives about 5000 B/s depending on compression,
+a double-B-channel ISDN line about 12800 B/s, and a T1 line is about
+150000 B/s.
+If you want to set a minimum rate as well, use number-number.
+.PP
+Example:
+.nf
+  # throttle file for www.acme.com
+
+  **              2000-100000  # limit total web usage to 2/3 of our T1,
+                               # but never go below 2000 B/s
+  **.jpg|**.gif   50000   # limit images to 1/3 of our T1
+  **.mpg          20000   # and movies to even less
+  jef/**          20000   # jef's pages are too popular
+.fi
+.PP
+Throttling is implemented by checking each incoming URL filename against all
+of the patterns in the throttle file.
+The server accumulates statistics on how much bandwidth each pattern
+has accounted for recently (via a rolling average).
+If a URL matches a pattern that has been exceeding its specified limit,
+then the data returned is actually slowed down, with
+pauses between each block.
+If that's not possible (e.g. for CGI programs) or if the bandwidth has gotten
+way larger than the limit, then the server returns a special code
+saying 'try again later'.
+.PP
+The minimum rates are implemented similarly.
+If too many people are trying to fetch something at the same time,
+throttling may slow down each connection so much that it's not really
+useable.
+Furthermore, all those slow connections clog up the server, using
+up file handles and connection slots.
+Setting a minimum rate says that past a certain point you should not
+even bother - the server returns the 'try again later" code and the
+connection isn't even started.
+.PP
+There is no provision for setting a maximum connections/second throttle,
+because throttling a request uses as much cpu as handling it, so
+there would be no point.
+There is also no provision for throttling the number of simultaneous
+connections on a per-URL basis.
+However you can control the overall number of connections for the whole
+server very simply, by setting the operating system's per-process file
+descriptor limit before starting thttpd.
+Be sure to set the hard limit, not the soft limit.
+.SH "MULTIHOMING"
+.PP
+Multihoming means using one machine to serve multiple hostnames.
+For instance, if you're an internet provider and you want to let
+all of your customers have customized web addresses, you might
+have www.joe.acme.com, www.jane.acme.com, and your own www.acme.com,
+all running on the same physical hardware.
+This feature is also known as "virtual hosts".
+There are three steps to setting this up.
+.PP
+One, make DNS entries for all of the hostnames.
+The current way to do this, allowed by HTTP/1.1, is to use CNAME aliases,
+like so:
+.nf
+  www.acme.com IN A 192.100.66.1
+  www.joe.acme.com IN CNAME www.acme.com
+  www.jane.acme.com IN CNAME www.acme.com
+.fi
+However, this is incompatible with older HTTP/1.0 browsers.
+If you want to stay compatible, there's a different way - use A records
+instead, each with a different IP address, like so:
+.nf
+  www.acme.com IN A 192.100.66.1
+  www.joe.acme.com IN A 192.100.66.200
+  www.jane.acme.com IN A 192.100.66.201
+.fi
+This is bad because it uses extra IP addresses, a somewhat scarce resource.
+But if you want people with older browsers to be able to visit your
+sites, you still have to do it this way.
+.PP
+Step two.
+If you're using the modern CNAME method of multihoming, then you can
+skip this step.
+Otherwise, using the older multiple-IP-address method you
+must set up IP aliases or multiple interfaces for the extra addresses.
+You can use ifconfig(8)'s alias command to tell the machine to answer to
+all of the different IP addresses.
+Example:
+.nf
+  ifconfig le0 www.acme.com
+  ifconfig le0 www.joe.acme.com alias
+  ifconfig le0 www.jane.acme.com alias
+.fi
+If your OS's version of ifconfig doesn't have an alias command, you're
+probably out of luck (but see http://www.acme.com/software/thttpd/notes.html).
+.PP
+Third and last, you must set up thttpd to handle the multiple hosts.
+The easiest way is with the -v flag, or the ALWAYS_VHOST config.h option.
+This works with either CNAME multihosting or multiple-IP multihosting.
+What it does is send each incoming request to a subdirectory based on the
+hostname it's intended for.
+All you have to do in order to set things up is to create those subdirectories
+in the directory where thttpd will run.
+With the example above, you'd do like so:
+.nf
+  mkdir www.acme.com www.joe.acme.com www.jane.acme.com
+.fi
+If you're using old-style multiple-IP multihosting, you should also create
+symbolic links from the numeric addresses to the names, like so:
+.nf
+  ln -s www.acme.com 192.100.66.1
+  ln -s www.joe.acme.com 192.100.66.200
+  ln -s www.jane.acme.com 192.100.66.201
+.fi
+This lets the older HTTP/1.0 browsers find the right subdirectory.
+.PP
+There's an optional alternate step three if you're using multiple-IP
+multihosting: run a separate thttpd process for each hostname, using
+the -h flag to specify which one is which.
+This gives you more flexibility, since you can run each of these processes
+in separate directories, with different throttle files, etc.
+Example:
+.nf
+  thttpd -r -d /usr/www -h www.acme.com
+  thttpd -r -d /usr/www/joe -u joe -h www.joe.acme.com
+  thttpd -r -d /usr/www/jane -u jane -h www.jane.acme.com
+.fi
+But remember, this multiple-process method does not work with CNAME
+multihosting - for that, you must use a single thttpd process with
+the -v flag.
+.SH "CUSTOM ERRORS"
+.PP
+thttpd lets you define your own custom error pages for the various
+HTTP errors.
+There's a separate file for each error number, all stored in one
+special directory.
+The directory name is "errors", at the top of the web directory tree.
+The error files should be named "errNNN.html", where NNN is the error number.
+So for example, to make a custom error page for the authentication failure
+error, which is number 401, you would put your HTML into the file
+"errors/err401.html".
+If no custom error file is found for a given error number, then the
+usual built-in error page is generated.
+.PP
+If you're using the virtual hosts option, you can also have different
+custom error pages for each different virtual host.
+In this case you put another "errors" directory in the top of that
+virtual host's web tree.
+thttpd will look first in the virtual host errors directory, and
+then in the server-wide errors directory, and if neither of those
+has an appropriate error file then it will generate the built-in error.
+.SH "NON-LOCAL REFERRERS"
+.PP
+Sometimes another site on the net will embed your image files in their
+HTML files, which basically means they're stealing your bandwidth.
+You can prevent them from doing this by using non-local referrer filtering.
+With this option, certain files can only be fetched via a local referrer.
+The files have to be referenced by a local web page.
+If a web page on some other site references the files, that fetch will
+be blocked.
+There are three config-file variables for this feature:
+.TP
+.B urlpat
+A wildcard pattern for the URLs that should require a local referrer.
+This is typically just image files, sound files, and so on.
+For example:
+.nf
+  urlpat=**.jpg|**.gif|**.au|**.wav
+.fi
+For most sites, that one setting is all you need to enable referrer filtering.
+.TP
+.B noemptyreferrers
+By default, requests with no referrer at all, or a null referrer, or a
+referrer with no apparent hostname, are allowed.
+With this variable set, such requests are disallowed.
+.TP
+.B localpat
+A wildcard pattern that specifies the local host or hosts.
+This is used to determine if the host in the referrer is local or not.
+If not specified it defaults to the actual local hostname.
+.SH SYMLINKS
+.PP
+thttpd is very picky about symbolic links.
+Before delivering any file, it first checks each element in the path
+to see if it's a symbolic link, and expands them all out to get the final
+actual filename.
+Along the way it checks for things like links with ".." that go above
+the server's directory, and absolute symlinks (ones that start with a /).
+These are prohibited as security holes, so the server returns an
+error page for them.
+This means you can't set up your web directory with a bunch of symlinks
+pointing to individual users' home web directories.
+Instead you do it the other way around - the user web directories are
+real subdirs of the main web directory, and in each user's home
+dir there's a symlink pointing to their actual web dir.
+.PP
+The CGI pattern is also affected - it gets matched against the fully-expanded
+filename.  So, if you have a single CGI directory but then put a symbolic
+link in it pointing somewhere else, that won't work.  The CGI program will be
+treated as a regular file and returned to the client, instead of getting run.
+This could be confusing.
+.SH PERMISSIONS
+.PP
+thttpd is also picky about file permissions.
+It wants data files (HTML, images) to be world readable.
+Readable by the group that the thttpd process runs as is not enough - thttpd
+checks explicitly for the world-readable bit.
+This is so that no one ever gets surprised by a file that's not set
+world-readable and yet somehow is readable by the HTTP server and
+therefore the *whole* world.
+.PP
+The same logic applies to directories.
+As with the standard Unix "ls" program, thttpd will only let you
+look at the contents of a directory if its read bit is on; but
+as with data files, this must be the world-read bit, not just the
+group-read bit.
+.PP
+thttpd also wants the execute bit to be *off* for data files.
+A file that is marked executable but doesn't match the CGI pattern
+might be a script or program that got accidentally left in the
+wrong directory.
+Allowing people to fetch the contents of the file might be a security breach,
+so this is prohibited.
+Of course if an executable file *does* match the CGI pattern, then it
+just gets run as a CGI.
+.PP
+In summary, data files should be mode 644 (rw-r--r--),
+directories should be 755 (rwxr-xr-x) if you want to allow indexing and
+711 (rwx--x--x) to disallow it, and CGI programs should be mode
+755 (rwxr-xr-x) or 711 (rwx--x--x).
+.SH LOGS
+.PP
+thttpd does all of its logging via syslog(3).
+The facility it uses is configurable.
+Aside from error messages, there are only a few log entry types of interest,
+all fairly similar to CERN Common Log Format:
+.nf
+  Aug  6 15:40:34 acme thttpd[583]: 165.113.207.103 - - "GET /file" 200 357
+  Aug  6 15:40:43 acme thttpd[583]: 165.113.207.103 - - "HEAD /file" 200 0
+  Aug  6 15:41:16 acme thttpd[583]: referrer http://www.acme.com/ -> /dir
+  Aug  6 15:41:16 acme thttpd[583]: user-agent Mozilla/1.1N
+.fi
+The package includes a script for translating these log entries info
+CERN-compatible files.
+Note that thttpd does not translate numeric IP addresses into domain names.
+This is both to save time and as a minor security measure (the numeric
+address is harder to spoof).
+.PP
+Relevant config.h option: LOG_FACILITY.
+.PP
+If you'd rather log directly to a file, you can use the -l command-line
+flag.  But note that error messages still go to syslog.
+.SH SIGNALS
+.PP
+thttpd handles a couple of signals, which you can send via the
+standard Unix kill(1) command:
+.TP
+.B INT,TERM
+These signals tell thttpd to shut down immediately.
+Any requests in progress get aborted.
+.TP
+.B USR1
+This signal tells thttpd to shut down as soon as it's done servicing
+all current requests.
+In addition, the network socket it uses to accept new connections gets
+closed immediately, which means a fresh thttpd can be started up
+immediately.
+.TP
+.B USR2
+This signal tells thttpd to generate the statistics syslog messages
+immediately, instead of waiting for the regular hourly update.
+.TP
+.B HUP
+This signal tells thttpd to close and re-open its (non-syslog) log file,
+for instance if you rotated the logs and want it to start using the
+new one.
+This is a little tricky to set up correctly, for instance if you are using
+chroot() then the log file must be within the chroot tree, but it's
+definitely doable.
+.SH "SEE ALSO"
+redirect(8), ssi(8), makeweb(1), htpasswd(1), syslogtocern(8), weblog_parse(1), http_get(1)
+.SH THANKS
+.PP
+Many thanks to contributors, reviewers, testers:
+John LoVerso, Jordan Hayes, Chris Torek, Jim Thompson, Barton Schaffer,
+Geoff Adams, Dan Kegel, John Hascall, Bennett Todd, KIKUCHI Takahiro,
+Catalin Ionescu.
+Special thanks to Craig Leres for substantial debugging and development,
+and for not complaining about my coding style very much.
+.SH AUTHOR
+Copyright © 1995,1998,1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
+All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
diff --git a/debian/thttpd/usr/local/sbin/thttpd b/debian/thttpd/usr/local/sbin/thttpd
new file mode 100755 (executable)
index 0000000..cc7e405
Binary files /dev/null and b/debian/thttpd/usr/local/sbin/thttpd differ
diff --git a/debian/thttpd/usr/share/doc/thttpd/README.Debian b/debian/thttpd/usr/share/doc/thttpd/README.Debian
new file mode 100644 (file)
index 0000000..f6f5b71
--- /dev/null
@@ -0,0 +1,6 @@
+thttpd for Debian
+----------------
+
+<possible notes regarding this package - if none, delete this file>
+
+ -- Ralph Ronnquist <ralph.ronnquist@gmail.com>  Sat, 07 Jul 2018 17:38:08 +1000
diff --git a/debian/thttpd/usr/share/doc/thttpd/changelog.Debian.gz b/debian/thttpd/usr/share/doc/thttpd/changelog.Debian.gz
new file mode 100644 (file)
index 0000000..60251ff
Binary files /dev/null and b/debian/thttpd/usr/share/doc/thttpd/changelog.Debian.gz differ
diff --git a/debian/thttpd/usr/share/doc/thttpd/copyright b/debian/thttpd/usr/share/doc/thttpd/copyright
new file mode 100644 (file)
index 0000000..e828fd4
--- /dev/null
@@ -0,0 +1,34 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: thttpd
+Source: <url://example.com>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+           <years> <likewise for another author>
+License: GPL-3.0+
+
+Files: debian/*
+Copyright: 2018 Ralph Ronnquist <ralph.ronnquist@gmail.com>
+License: GPL-3.0+
+
+License: GPL-3.0+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+# Please avoid picking licenses with terms that are more restrictive than the
+# packaged work, as it may make Debian's contributions unacceptable upstream.
diff --git a/debian/watch.ex b/debian/watch.ex
new file mode 100644 (file)
index 0000000..dcd3aaf
--- /dev/null
@@ -0,0 +1,38 @@
+# Example watch control file for uscan
+# Rename this file to "watch" and then you can run the "uscan" command
+# to check for upstream updates and more.
+# See uscan(1) for format
+
+# Compulsory line, this is a version 4 file
+version=4
+
+# PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig
+#opts="pgpsigurlmangle=s%$%.sig%"
+
+# HTTP site (basic)
+#http://example.com/downloads.html \
+#  files/thttpd-([\d\.]+)\.tar\.gz debian uupdate
+
+# Uncommment to examine a FTP server
+#ftp://ftp.example.com/pub/thttpd-(.*)\.tar\.gz debian uupdate
+
+# SourceForge hosted projects
+# http://sf.net/thttpd/ thttpd-(.*)\.tar\.gz debian uupdate
+
+# GitHub hosted projects
+#opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%<project>-$1.tar.gz%" \
+#   https://github.com/<user>/thttpd/tags \
+#   (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate
+
+# PyPI
+# https://pypi.debian.net/thttpd/thttpd-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
+
+# Direct Git
+# opts="mode=git" http://git.example.com/thttpd.git \
+#   refs/tags/v([\d\.]+) debian uupdate
+
+
+
+
+# Uncomment to find new files on GooglePages
+# http://example.googlepages.com/foo.html thttpd-(.*)\.tar\.gz
diff --git a/extras/Makefile b/extras/Makefile
new file mode 100644 (file)
index 0000000..781980f
--- /dev/null
@@ -0,0 +1,87 @@
+# Generated automatically from Makefile.in by configure.
+# Makefile for extras.
+#
+# Copyright © 1995,1998 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+prefix =       /usr/local
+exec_prefix =  ${prefix}
+BINDIR =       ${exec_prefix}/sbin
+WEBDIR =       $(prefix)/www
+CGIBINDIR =    $(WEBDIR)/cgi-bin
+MANDIR =       /usr/local/man
+
+CC =           gcc
+CCOPT =                -O2
+DEFS =          -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 
+INCLS =                -I..
+CFLAGS =       $(CCOPT) $(DEFS) $(INCLS)
+STATICFLAG =   
+LDFLAGS =      
+LIBS =         -lcrypt 
+NETLIBS =      
+INSTALL =      /usr/bin/install -c
+
+CLEANFILES =   *.o makeweb htpasswd
+
+
+
+.c.o:
+       @rm -f $@
+       $(CC) $(CFLAGS) -c $*.c
+
+all:           makeweb htpasswd
+
+makeweb:       makeweb.o
+       $(CC) $(LDFLAGS) makeweb.o -o makeweb $(LIBS) $(NETLIBS)
+
+makeweb.o:     makeweb.c ../config.h
+       $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c makeweb.c
+
+htpasswd:      htpasswd.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) htpasswd.o -o htpasswd $(LIBS)
+
+htpasswd.o:    htpasswd.c ../config.h
+       $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c htpasswd.c
+
+
+install:       all
+       rm -f $(BINDIR)/makeweb $(BINDIR)/htpasswd $(BINDIR)/syslogtocern
+       cp makeweb $(BINDIR)/makeweb
+       chgrp $(WEBGROUP) $(BINDIR)/makeweb
+       chmod 2755 $(BINDIR)/makeweb
+       cp htpasswd $(BINDIR)/htpasswd
+       cp syslogtocern $(BINDIR)/syslogtocern
+       rm -f $(MANDIR)/man1/makeweb.1
+       cp makeweb.1 $(MANDIR)/man1/makeweb.1
+       rm -f $(MANDIR)/man1/htpasswd.1
+       cp htpasswd.1 $(MANDIR)/man1/htpasswd.1
+       rm -f $(MANDIR)/man8/syslogtocern.8
+       cp syslogtocern.8 $(MANDIR)/man8/syslogtocern.8
+
+clean:
+       rm -f $(CLEANFILES)
+
+distclean:
+       rm -f $(CLEANFILES) Makefile
diff --git a/extras/Makefile.in b/extras/Makefile.in
new file mode 100644 (file)
index 0000000..a29780f
--- /dev/null
@@ -0,0 +1,86 @@
+# Makefile for extras.
+#
+# Copyright © 1995,1998 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+prefix =       @prefix@
+exec_prefix =  @exec_prefix@
+BINDIR =       @sbindir@
+WEBDIR =       $(prefix)/www
+CGIBINDIR =    $(WEBDIR)/cgi-bin
+MANDIR =       @mandir@
+
+CC =           @CC@
+CCOPT =                @V_CCOPT@
+DEFS =         @DEFS@
+INCLS =                -I..
+CFLAGS =       $(CCOPT) $(DEFS) $(INCLS)
+STATICFLAG =   @V_STATICFLAG@
+LDFLAGS =      @LDFLAGS@
+LIBS =         @LIBS@
+NETLIBS =      @V_NETLIBS@
+INSTALL =      @INSTALL@
+
+CLEANFILES =   *.o makeweb htpasswd
+
+@SET_MAKE@
+
+.c.o:
+       @rm -f $@
+       $(CC) $(CFLAGS) -c $*.c
+
+all:           makeweb htpasswd
+
+makeweb:       makeweb.o
+       $(CC) $(LDFLAGS) makeweb.o -o makeweb $(LIBS) $(NETLIBS)
+
+makeweb.o:     makeweb.c ../config.h
+       $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c makeweb.c
+
+htpasswd:      htpasswd.o
+       $(CC) $(LDFLAGS) $(STATICFLAG) htpasswd.o -o htpasswd $(LIBS)
+
+htpasswd.o:    htpasswd.c ../config.h
+       $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c htpasswd.c
+
+
+install:       all
+       rm -f $(BINDIR)/makeweb $(BINDIR)/htpasswd $(BINDIR)/syslogtocern
+       cp makeweb $(BINDIR)/makeweb
+       chgrp $(WEBGROUP) $(BINDIR)/makeweb
+       chmod 2755 $(BINDIR)/makeweb
+       cp htpasswd $(BINDIR)/htpasswd
+       cp syslogtocern $(BINDIR)/syslogtocern
+       rm -f $(MANDIR)/man1/makeweb.1
+       cp makeweb.1 $(MANDIR)/man1/makeweb.1
+       rm -f $(MANDIR)/man1/htpasswd.1
+       cp htpasswd.1 $(MANDIR)/man1/htpasswd.1
+       rm -f $(MANDIR)/man8/syslogtocern.8
+       cp syslogtocern.8 $(MANDIR)/man8/syslogtocern.8
+
+clean:
+       rm -f $(CLEANFILES)
+
+distclean:
+       rm -f $(CLEANFILES) Makefile
diff --git a/extras/htpasswd.1 b/extras/htpasswd.1
new file mode 100644 (file)
index 0000000..1124b02
--- /dev/null
@@ -0,0 +1,16 @@
+.TH htpasswd 1 "05 May 1998"
+.SH NAME
+htpasswd - manipulate HTTP-server password files
+.SH SYNOPSIS
+.B htpasswd
+.RB [ -c ]
+.I passwordfile
+.I username
+.SH DESCRIPTION
+.PP
+Sets a user's password in an httpd-style password file.
+The -c flag creates a new file.
+.SH AUTHOR
+Rob McCool.
+Modified 29aug97 by Jef Poskanzer to accept new password on stdin,
+if stdin is a pipe or file.  This is necessary for use from CGI.
diff --git a/extras/htpasswd.c b/extras/htpasswd.c
new file mode 100644 (file)
index 0000000..31ac769
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * htpasswd.c: simple program for manipulating password file for NCSA httpd
+ * 
+ * Rob McCool
+ */
+
+/* Modified 29aug97 by Jef Poskanzer to accept new password on stdin,
+** if stdin is a pipe or file.  This is necessary for use from CGI.
+*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LF 10
+#define CR 13
+
+#define MAX_STRING_LEN 256
+
+int tfd;
+char temp_template[] = "/tmp/htp.XXXXXX";
+
+void interrupted(int);
+
+static char * strd(char *s) {
+    char *d;
+
+    d=(char *)malloc(strlen(s) + 1);
+    strcpy(d,s);
+    return(d);
+}
+
+static void getword(char *word, char *line, char stop) {
+    int x = 0,y;
+
+    for(x=0;((line[x]) && (line[x] != stop));x++)
+        word[x] = line[x];
+
+    word[x] = '\0';
+    if(line[x]) ++x;
+    y=0;
+
+    while((line[y++] = line[x++]));
+}
+
+static int my_getline(char *s, int n, FILE *f) {
+    int i=0;
+
+    while(1) {
+        s[i] = (char)fgetc(f);
+
+        if(s[i] == CR)
+            s[i] = fgetc(f);
+
+        if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
+            s[i] = '\0';
+            return (feof(f) ? 1 : 0);
+        }
+        ++i;
+    }
+}
+
+static void putline(FILE *f,char *l) {
+    int x;
+
+    for(x=0;l[x];x++) fputc(l[x],f);
+    fputc('\n',f);
+}
+
+
+/* From local_passwd.c (C) Regents of Univ. of California blah blah */
+static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void to64(char *s, long v, int n) {
+    while (--n >= 0) {
+        *s++ = itoa64[v&0x3f];
+        v >>= 6;
+    }
+}
+
+#ifdef MPE
+/* MPE lacks getpass() and a way to suppress stdin echo.  So for now, just
+issue the prompt and read the results with echo.  (Ugh). */
+
+char *getpass(const char *prompt) {
+
+static char password[81];
+
+fputs(prompt,stderr);
+gets((char *)&password);
+
+if (strlen((char *)&password) > 8) {
+  password[8]='\0';
+}
+
+return (char *)&password;
+}
+#endif
+
+static void
+add_password( char* user, FILE* f )
+    {
+    char pass[100];
+    char* pw;
+    char* cpw;
+    char salt[3];
+
+    if ( ! isatty( fileno( stdin ) ) )
+       {
+       (void) fgets( pass, sizeof(pass), stdin );
+       if ( pass[strlen(pass) - 1] == '\n' )
+           pass[strlen(pass) - 1] = '\0';
+       pw = pass;
+       }
+    else
+       {
+       pw = strd( (char*) getpass( "New password:" ) );
+       if ( strcmp( pw, (char*) getpass( "Re-type new password:" ) ) != 0 )
+           {
+           (void) fprintf( stderr, "They don't match, sorry.\n" );
+           if ( tfd != -1 )
+               unlink( temp_template );
+           exit( 1 );
+           }
+       }
+    (void) srandom( (int) time( (time_t*) 0 ) );
+    to64( &salt[0], random(), 2 );
+    cpw = crypt( pw, salt );
+    (void) fprintf( f, "%s:%s\n", user, cpw );
+    }
+
+static void usage(void) {
+    fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n");
+    fprintf(stderr,"The -c flag creates a new file.\n");
+    exit(1);
+}
+
+void interrupted(int signo) {
+    fprintf(stderr,"Interrupted.\n");
+    if(tfd != -1) unlink(temp_template);
+    exit(1);
+}
+
+int main(int argc, char *argv[]) {
+    FILE *tfp,*f;
+    char user[MAX_STRING_LEN];
+    char line[MAX_STRING_LEN];
+    char l[MAX_STRING_LEN];
+    char w[MAX_STRING_LEN];
+    char command[MAX_STRING_LEN];
+    int found;
+
+    tfd = -1;
+    signal(SIGINT,(void (*)(int))interrupted);
+    if(argc == 4) {
+        if(strcmp(argv[1],"-c"))
+            usage();
+        if(!(tfp = fopen(argv[2],"w"))) {
+            fprintf(stderr,"Could not open passwd file %s for writing.\n",
+                    argv[2]);
+            perror("fopen");
+            exit(1);
+        }
+        printf("Adding password for %s.\n",argv[3]);
+        add_password(argv[3],tfp);
+        fclose(tfp);
+        exit(0);
+    } else if(argc != 3) usage();
+
+    tfd = mkstemp(temp_template);
+    if(!(tfp = fdopen(tfd,"w"))) {
+        fprintf(stderr,"Could not open temp file.\n");
+        exit(1);
+    }
+
+    if(!(f = fopen(argv[1],"r"))) {
+        fprintf(stderr,
+                "Could not open passwd file %s for reading.\n",argv[1]);
+        fprintf(stderr,"Use -c option to create new one.\n");
+        exit(1);
+    }
+    strncpy(user,argv[2],sizeof(user)-1);
+    user[sizeof(user)-1] = '\0';
+
+    found = 0;
+    while(!(my_getline(line,MAX_STRING_LEN,f))) {
+        if(found || (line[0] == '#') || (!line[0])) {
+            putline(tfp,line);
+            continue;
+        }
+        strcpy(l,line);
+        getword(w,l,':');
+        if(strcmp(user,w)) {
+            putline(tfp,line);
+            continue;
+        }
+        else {
+            printf("Changing password for user %s\n",user);
+            add_password(user,tfp);
+            found = 1;
+        }
+    }
+    if(!found) {
+        printf("Adding user %s\n",user);
+        add_password(user,tfp);
+    }
+    fclose(f);
+    fclose(tfp);
+    sprintf(command,"cp %s %s",temp_template,argv[1]);
+    system(command);
+    unlink(temp_template);
+    exit(0);
+}
diff --git a/extras/makeweb.1 b/extras/makeweb.1
new file mode 100644 (file)
index 0000000..ff729c9
--- /dev/null
@@ -0,0 +1,34 @@
+.TH makeweb 1 "06 September 1995"
+.SH NAME
+makeweb - create user web directory
+.SH SYNOPSIS
+.B makeweb
+.SH DESCRIPTION
+.PP
+This program allows users to create their own web subdirectories off
+of the main web directory.
+.SH "SEE ALSO
+thttpd(8)
+.SH AUTHOR
+Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
diff --git a/extras/makeweb.c b/extras/makeweb.c
new file mode 100644 (file)
index 0000000..aa7b22f
--- /dev/null
@@ -0,0 +1,256 @@
+/* makeweb.c - let a user create a web subdirectory
+**
+** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+/* This is intended to be installed setgid to a group that has
+** write access to the system web directory.  It allows any user
+** to create a subdirectory there.  It also makes a symbolic link
+** in the user's home directory pointing at the new web subdir.
+*/
+
+
+#include "../config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#define LINK "public_html"
+
+static char* argv0;
+
+
+static void
+check_room( int size, int len )
+    {
+    if ( len > size )
+       {
+       (void) fprintf( stderr, "%s: internal error, out of room\n", argv0 );
+       exit( 1 );
+       }
+    }
+
+
+static void
+end_with_slash( char* str )
+    {
+    if ( str[strlen( str ) - 1] != '/' )
+       (void) strcat( str, "/" );
+    }
+
+
+static void
+check_dir( char* dirname, uid_t uid, gid_t gid )
+    {
+    struct stat sb;
+
+    /* Check the directory. */
+    if ( stat( dirname, &sb ) < 0 )
+       {
+       if ( errno != ENOENT )
+           {
+           perror( dirname );
+           exit( 1 );
+           }
+       /* Doesn't exist.  Try to make it. */
+       if ( mkdir( dirname, 0755 ) < 0 )
+           {
+           if ( errno == ENOENT )
+               (void) printf( "\
+Some part of the path %s does not exist.\n\
+This is probably a configuration error.\n", dirname );
+           else
+               perror( dirname );
+           exit( 1 );
+           }
+       (void) printf( "Created web directory %s\n", dirname );
+       /* Try to change the group of the new dir to the user's group. */
+       (void) chown( dirname, -1, gid );
+       }
+    else
+       {
+       /* The directory already exists.  Well, check that it is in
+       ** fact a directory.
+       */
+       if ( ! S_ISDIR( sb.st_mode ) )
+           {
+           (void) printf(
+               "%s already exists but is not a directory!\n", dirname );
+           exit( 1 );
+           }
+       if ( sb.st_uid != uid )
+           {
+           (void) printf(
+               "%s already exists but you don't own it!\n", dirname );
+           exit( 1 );
+           }
+       (void) printf( "Web directory %s already existed.\n", dirname );
+       }
+    }
+
+
+int
+main( int argc, char** argv )
+    {
+    char* webdir;
+    char* prefix;
+    struct passwd* pwd;
+    char* username;
+    char* homedir;
+    char dirname[5000];
+    char linkname[5000];
+    char linkbuf[5000];
+    struct stat sb;
+
+    argv0 = argv[0];
+    if ( argc != 1 )
+       {
+       (void) fprintf( stderr, "usage:  %s\n", argv0 );
+       exit( 1 );
+       }
+
+    pwd = getpwuid( getuid() );
+    if ( pwd == (struct passwd*) 0 )
+       {
+       (void) fprintf( stderr, "%s: can't find your username\n", argv0 );
+       exit( 1 );
+       }
+    username = pwd->pw_name;
+    homedir = pwd->pw_dir;
+
+#ifdef TILDE_MAP_2
+
+    /* All we have to do for the TILDE_MAP_2 case is make sure there's
+    ** a public_html subdirectory.
+    */
+    check_room(
+       sizeof(dirname), strlen( homedir ) + strlen( TILDE_MAP_2 ) + 2 );
+    (void) strcpy( dirname, homedir );
+    end_with_slash( dirname );
+    (void) strcat( dirname, TILDE_MAP_2 );
+
+    check_dir( dirname, pwd->pw_uid, pwd->pw_gid );
+
+#else /* TILDE_MAP_2 */
+
+    /* Gather the pieces. */
+    webdir = WEBDIR;
+#ifdef TILDE_MAP_1
+    prefix = TILDE_MAP_1;
+#else /* TILDE_MAP_1 */
+    prefix = "";
+#endif /* TILDE_MAP_1 */
+
+    /* Assemble the directory name.  Be paranoid cause we're sgid. */
+    check_room(
+       sizeof(dirname),
+       strlen( webdir ) + strlen( prefix ) + strlen( username ) + 3 );
+    (void) strcpy( dirname, webdir );
+    end_with_slash( dirname );
+    if ( strlen( prefix ) != 0 )
+       {
+       (void) strcat( dirname, prefix );
+       end_with_slash( dirname );
+       }
+    (void) strcat( dirname, username );
+
+    /* Assemble the link name. */
+    check_room( sizeof(linkname), strlen( homedir ) + strlen( LINK ) + 2 );
+    (void) strcpy( linkname, homedir );
+    end_with_slash( linkname );
+    (void) strcat( linkname, LINK );
+
+    check_dir( dirname, pwd->pw_uid, pwd->pw_gid );
+
+    /* Check the symlink. */
+    try_link_again: ;
+    if ( lstat( linkname, &sb ) < 0 )
+       {
+       if ( errno != ENOENT )
+           {
+           perror( linkname );
+           exit( 1 );
+           }
+       /* Doesn't exist.  Try to make it. */
+       if ( symlink( dirname, linkname ) < 0 )
+           {
+           if ( errno == ENOENT )
+               (void) printf( "\
+Some part of the path %s does not exist.\n\
+This is probably a configuration error.\n", linkname );
+           else
+               perror( linkname );
+           exit( 1 );
+           }
+       (void) printf( "Created symbolic link %s\n", linkname );
+       }
+    else
+       {
+       /* The link already exists.  Well, check that it is in
+       ** fact a link.
+       */
+       if ( ! S_ISLNK( sb.st_mode ) )
+           {
+           (void) printf( "\
+%s already exists but is not a\n\
+symbolic link!  Perhaps you have a real web subdirectory in your\n\
+home dir from a previous web server configuration?  You may have\n\
+to rename it, run %s again, and then copy in the old\n\
+contents.\n", linkname, argv0 );
+           exit( 1 );
+           }
+       /* Check the existing link's contents. */
+       if ( readlink( linkname, linkbuf, sizeof(linkbuf) ) < 0 )
+           {
+           perror( linkname );
+           exit( 1 );
+           }
+       if ( strcmp( dirname, linkbuf ) == 0 )
+           (void) printf( "Symbolic link %s already existed.\n", linkname );
+       else
+           {
+           (void) printf( "\
+Symbolic link %s already existed\n\
+but it points to the wrong place!  Attempting to remove and\n\
+recreate it.\n", linkname );
+           if ( unlink( linkname ) < 0 )
+               {
+               perror( linkname );
+               exit( 1 );
+               }
+           goto try_link_again;
+           }
+       }
+#endif /* TILDE_MAP_2 */
+
+    exit( 0 );
+    }
diff --git a/extras/syslogtocern b/extras/syslogtocern
new file mode 100755 (executable)
index 0000000..d4a6dfa
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh
+#
+# syslogtocern - convert thttpd syslog entries into CERN Combined Log Format
+#
+# Copyright © 1995,1998 by Jef Poskanzer <jef@mail.acme.com>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+if [ $# -lt 1 ] ; then
+    echo "usage:  $0 logfile ..." >&2
+    exit 1
+fi
+
+tmp1=/tmp/stc1.$$
+rm -f $tmp1
+
+# Gather up all the thttpd entries.
+egrep -h ' thttpd\[' "$@" > $tmp1
+
+# Figure out the current year - it's not in syslog's output.  Some versions
+# of date have the %Y directive to give the full four-digit year, but others
+# only have %y.
+year=`date +%y`
+if [ $year -gt 70 ] ; then
+    year=19$year
+else
+    year=20$year
+fi
+
+# If the current year isn't the year that the logfile was generated, we need
+# to fix it.  This will most likely happen once a year, when this script is
+# run on January 1st for December 31st's logfile.  So, if the current month
+# is January and there are December dates in the log file, we subtract one.
+# This should cover most cases.
+if [ `date +%m` -eq 1 -a `head -1 $tmp1 | awk '{print $1}'` = "Dec" ] ; then
+    year=`echo $year - 1 | bc`
+fi
+
+# Do access_log.
+awk < $tmp1 '{if ( NF >= 15 && $7 == "-" && $12 >= 100 && $12 < 510) print;}' |
+  sed -e "s,\([A-Z][a-z][a-z]\) \([0-9 ][0-9]\) \([0-9][0-9]:[0-9][0-9]:[0-9][0-9]\) [^ ]* thttpd\[[0-9]*\]: \([^ ]* [^ ]* [^ ]*\) \(.*\),\4 [\2/\1/${year}:\3] \5," -e 's,\[ ,[0,' > access_log
+
+# Do error_log.
+awk < $tmp1 '{if ( ! ( NF >= 15 && $7 == "-" && $12 >= 100 && $12 < 510) ) print;}' |
+  sed -e "s,\([A-Z][a-z][a-z] [0-9 ][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\) [^ ]* thttpd\[[0-9]*\]: \(.*\),[\1 ${year}] \2," > error_log
+
+# Done.
+rm -f $tmp1
diff --git a/extras/syslogtocern.8 b/extras/syslogtocern.8
new file mode 100644 (file)
index 0000000..351e385
--- /dev/null
@@ -0,0 +1,45 @@
+.TH syslogtocern 8 "12 October 1995"
+.SH NAME
+syslogtocern - convert thttpd syslog entries into CERN Common Log format
+.SH SYNOPSIS
+.B syslogtocern
+.I logfile
+.RI ...
+.SH DESCRIPTION
+.PP
+Reads one or more syslog files as input.
+Takes the thttpd entries, and converts them into CERN Combined Common
+Log format.
+Produces two files as output: access_log and error_log.
+If files with those names already exist in the current directory, they
+are overwritten.
+.SH "SEE ALSO"
+thttpd(8)
+.SH "BUGS / DEFICIENCIES"
+Lumps all thttpd processes together.
+It ought to produce separate files for each, identified by IP address and
+port number.
+However, that change represents a huge increase in complexity, so next version.
+.SH AUTHOR
+Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
diff --git a/fdwatch.c b/fdwatch.c
new file mode 100644 (file)
index 0000000..2b3de74
--- /dev/null
+++ b/fdwatch.c
@@ -0,0 +1,834 @@
+/* fdwatch.c - fd watcher routines, either select() or poll()
+**
+** Copyright © 1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <syslog.h>
+#include <fcntl.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else /* HAVE_POLL_H */
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif /* HAVE_SYS_POLL_H */
+#endif /* HAVE_POLL_H */
+
+#ifdef HAVE_SYS_DEVPOLL_H
+#include <sys/devpoll.h>
+#ifndef HAVE_DEVPOLL
+#define HAVE_DEVPOLL
+#endif /* !HAVE_DEVPOLL */
+#endif /* HAVE_SYS_DEVPOLL_H */
+
+#ifdef HAVE_SYS_EVENT_H
+#include <sys/event.h>
+#endif /* HAVE_SYS_EVENT_H */
+
+#include "fdwatch.h"
+
+#ifdef HAVE_SELECT
+#ifndef FD_SET
+#define NFDBITS         32
+#define FD_SETSIZE      32
+#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)      bzero((char*)(p), sizeof(*(p)))
+#endif /* !FD_SET */
+#endif /* HAVE_SELECT */
+
+static int nfiles;
+static long nwatches;
+static int* fd_rw;
+static void** fd_data;
+static int nreturned, next_ridx;
+
+#ifdef HAVE_KQUEUE
+
+#define WHICH                  "kevent"
+#define INIT( nf )         kqueue_init( nf )
+#define ADD_FD( fd, rw )       kqueue_add_fd( fd, rw )
+#define DEL_FD( fd )           kqueue_del_fd( fd )
+#define WATCH( timeout_msecs ) kqueue_watch( timeout_msecs )
+#define CHECK_FD( fd )         kqueue_check_fd( fd )
+#define GET_FD( ridx )         kqueue_get_fd( ridx )
+
+static int kqueue_init( int nf );
+static void kqueue_add_fd( int fd, int rw );
+static void kqueue_del_fd( int fd );
+static int kqueue_watch( long timeout_msecs );
+static int kqueue_check_fd( int fd );
+static int kqueue_get_fd( int ridx );
+
+#else /* HAVE_KQUEUE */
+# ifdef HAVE_DEVPOLL
+
+#define WHICH                  "devpoll"
+#define INIT( nf )         devpoll_init( nf )
+#define ADD_FD( fd, rw )       devpoll_add_fd( fd, rw )
+#define DEL_FD( fd )           devpoll_del_fd( fd )
+#define WATCH( timeout_msecs ) devpoll_watch( timeout_msecs )
+#define CHECK_FD( fd )         devpoll_check_fd( fd )
+#define GET_FD( ridx )         devpoll_get_fd( ridx )
+
+static int devpoll_init( int nf );
+static void devpoll_add_fd( int fd, int rw );
+static void devpoll_del_fd( int fd );
+static int devpoll_watch( long timeout_msecs );
+static int devpoll_check_fd( int fd );
+static int devpoll_get_fd( int ridx );
+
+# else /* HAVE_DEVPOLL */
+#  ifdef HAVE_POLL
+
+#define WHICH                  "poll"
+#define INIT( nf )         poll_init( nf )
+#define ADD_FD( fd, rw )       poll_add_fd( fd, rw )
+#define DEL_FD( fd )           poll_del_fd( fd )
+#define WATCH( timeout_msecs ) poll_watch( timeout_msecs )
+#define CHECK_FD( fd )         poll_check_fd( fd )
+#define GET_FD( ridx )         poll_get_fd( ridx )
+
+static int poll_init( int nf );
+static void poll_add_fd( int fd, int rw );
+static void poll_del_fd( int fd );
+static int poll_watch( long timeout_msecs );
+static int poll_check_fd( int fd );
+static int poll_get_fd( int ridx );
+
+#  else /* HAVE_POLL */
+#   ifdef HAVE_SELECT
+
+#define WHICH                  "select"
+#define INIT( nf )         select_init( nf )
+#define ADD_FD( fd, rw )       select_add_fd( fd, rw )
+#define DEL_FD( fd )           select_del_fd( fd )
+#define WATCH( timeout_msecs ) select_watch( timeout_msecs )
+#define CHECK_FD( fd )         select_check_fd( fd )
+#define GET_FD( ridx )         select_get_fd( ridx )
+
+static int select_init( int nf );
+static void select_add_fd( int fd, int rw );
+static void select_del_fd( int fd );
+static int select_watch( long timeout_msecs );
+static int select_check_fd( int fd );
+static int select_get_fd( int ridx );
+
+#   endif /* HAVE_SELECT */
+#  endif /* HAVE_POLL */
+# endif /* HAVE_DEVPOLL */
+#endif /* HAVE_KQUEUE */
+
+
+/* Routines. */
+
+/* Figure out how many file descriptors the system allows, and
+** initialize the fdwatch data structures.  Returns -1 on failure.
+*/
+int
+fdwatch_get_nfiles( void )
+    {
+    int i;
+#ifdef RLIMIT_NOFILE
+    struct rlimit rl;
+#endif /* RLIMIT_NOFILE */
+
+    /* Figure out how many fd's we can have. */
+    nfiles = getdtablesize();
+#ifdef RLIMIT_NOFILE
+    /* If we have getrlimit(), use that, and attempt to raise the limit. */
+    if ( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
+       {
+       nfiles = rl.rlim_cur;
+       if ( rl.rlim_max == RLIM_INFINITY )
+           rl.rlim_cur = 8192;         /* arbitrary */
+       else if ( rl.rlim_max > rl.rlim_cur )
+           rl.rlim_cur = rl.rlim_max;
+       if ( setrlimit( RLIMIT_NOFILE, &rl ) == 0 )
+           nfiles = rl.rlim_cur;
+       }
+#endif /* RLIMIT_NOFILE */
+
+#if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) )
+    /* If we use select(), then we must limit ourselves to FD_SETSIZE. */
+    nfiles = MIN( nfiles, FD_SETSIZE );
+#endif /* HAVE_SELECT && ! ( HAVE_POLL || HAVE_DEVPOLL || HAVE_KQUEUE ) */
+
+    /* Initialize the fdwatch data structures. */
+    nwatches = 0;
+    fd_rw = (int*) malloc( sizeof(int) * nfiles );
+    fd_data = (void**) malloc( sizeof(void*) * nfiles );
+    if ( fd_rw == (int*) 0 || fd_data == (void**) 0 )
+       return -1;
+    for ( i = 0; i < nfiles; ++i )
+       fd_rw[i] = -1;
+    if ( INIT( nfiles ) == -1 )
+       return -1;
+
+    return nfiles;
+    }
+
+
+/* Add a descriptor to the watch list.  rw is either FDW_READ or FDW_WRITE.  */
+void
+fdwatch_add_fd( int fd, void* client_data, int rw )
+    {
+    if ( fd < 0 || fd >= nfiles || fd_rw[fd] != -1 )
+       {
+       syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_add_fd!", fd );
+       return;
+       }
+    ADD_FD( fd, rw );
+    fd_rw[fd] = rw;
+    fd_data[fd] = client_data;
+    }
+
+
+/* Remove a descriptor from the watch list. */
+void
+fdwatch_del_fd( int fd )
+    {
+    if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 )
+       {
+       syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_del_fd!", fd );
+       return;
+       }
+    DEL_FD( fd );
+    fd_rw[fd] = -1;
+    fd_data[fd] = (void*) 0;
+    }
+
+/* Do the watch.  Return value is the number of descriptors that are ready,
+** or 0 if the timeout expired, or -1 on errors.  A timeout of INFTIM means
+** wait indefinitely.
+*/
+int
+fdwatch( long timeout_msecs )
+    {
+    ++nwatches;
+    nreturned = WATCH( timeout_msecs );
+    next_ridx = 0;
+    return nreturned;
+    }
+
+
+/* Check if a descriptor was ready. */
+int
+fdwatch_check_fd( int fd )
+    {
+    if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 )
+       {
+       syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_check_fd!", fd );
+       return 0;
+       }
+    return CHECK_FD( fd );
+    }
+
+
+void*
+fdwatch_get_next_client_data( void )
+    {
+    int fd;
+
+    if ( next_ridx >= nreturned )
+       return (void*) -1;
+    fd = GET_FD( next_ridx++ );
+    if ( fd < 0 || fd >= nfiles )
+       return (void*) 0;
+    return fd_data[fd];
+    }
+
+
+/* Generate debugging statistics syslog message. */
+void
+fdwatch_logstats( long secs )
+    {
+    if ( secs > 0 )
+       syslog(
+           LOG_NOTICE, "  fdwatch - %ld %ss (%g/sec)",
+           nwatches, WHICH, (float) nwatches / secs );
+    nwatches = 0;
+    }
+
+
+#ifdef HAVE_KQUEUE
+
+static int maxkqevents;
+static struct kevent* kqevents;
+static int nkqevents;
+static struct kevent* kqrevents;
+static int* kqrfdidx;
+static int kq;
+
+
+static int
+kqueue_init( int nf )
+    {
+    kq = kqueue();
+    if ( kq == -1 )
+       return -1;
+    maxkqevents = nf * 2;
+    kqevents = (struct kevent*) malloc( sizeof(struct kevent) * maxkqevents );
+    kqrevents = (struct kevent*) malloc( sizeof(struct kevent) * nf );
+    kqrfdidx = (int*) malloc( sizeof(int) * nf );
+    if ( kqevents == (struct kevent*) 0 || kqrevents == (struct kevent*) 0 ||
+        kqrfdidx == (int*) 0 )
+       return -1;
+    (void) memset( kqevents, 0, sizeof(struct kevent) * maxkqevents );
+    (void) memset( kqrfdidx, 0, sizeof(int) * nf );
+    return 0;
+    }
+
+
+static void
+kqueue_add_fd( int fd, int rw )
+    {
+    if ( nkqevents >= maxkqevents )
+       {
+       syslog( LOG_ERR, "too many kqevents in kqueue_add_fd!" );
+       return;
+       }
+    kqevents[nkqevents].ident = fd;
+    kqevents[nkqevents].flags = EV_ADD;
+    switch ( rw )
+       {
+       case FDW_READ: kqevents[nkqevents].filter = EVFILT_READ; break;
+       case FDW_WRITE: kqevents[nkqevents].filter = EVFILT_WRITE; break;
+       default: break;
+       }
+    ++nkqevents;
+    }
+
+
+static void
+kqueue_del_fd( int fd )
+    {
+    if ( nkqevents >= maxkqevents )
+       {
+       syslog( LOG_ERR, "too many kqevents in kqueue_del_fd!" );
+       return;
+       }
+    kqevents[nkqevents].ident = fd;
+    kqevents[nkqevents].flags = EV_DELETE;
+    switch ( fd_rw[fd] )
+       {
+       case FDW_READ: kqevents[nkqevents].filter = EVFILT_READ; break;
+       case FDW_WRITE: kqevents[nkqevents].filter = EVFILT_WRITE; break;
+       }
+    ++nkqevents;
+    }
+
+
+static int
+kqueue_watch( long timeout_msecs )
+    {
+    int i, r;
+
+    if ( timeout_msecs == INFTIM )
+       r = kevent(
+           kq, kqevents, nkqevents, kqrevents, nfiles, (struct timespec*) 0 );
+    else
+       {
+       struct timespec ts;
+       ts.tv_sec = timeout_msecs / 1000L;
+       ts.tv_nsec = ( timeout_msecs % 1000L ) * 1000000L;
+       r = kevent( kq, kqevents, nkqevents, kqrevents, nfiles, &ts );
+       }
+    nkqevents = 0;
+    if ( r == -1 )
+       return -1;
+
+    for ( i = 0; i < r; ++i )
+       kqrfdidx[kqrevents[i].ident] = i;
+
+    return r;
+    }
+
+
+static int
+kqueue_check_fd( int fd )
+    {
+    int ridx = kqrfdidx[fd];
+
+    if ( ridx < 0 || ridx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad ridx (%d) in kqueue_check_fd!", ridx );
+       return 0;
+       }
+    if ( ridx >= nreturned ) 
+       return 0;
+    if ( kqrevents[ridx].ident != fd )
+       return 0;
+    if ( kqrevents[ridx].flags & EV_ERROR )
+       return 0;
+    switch ( fd_rw[fd] )
+       {
+       case FDW_READ: return kqrevents[ridx].filter == EVFILT_READ;
+       case FDW_WRITE: return kqrevents[ridx].filter == EVFILT_WRITE;
+       default: return 0;
+       }
+    }
+
+
+static int
+kqueue_get_fd( int ridx )
+    {
+    if ( ridx < 0 || ridx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad ridx (%d) in kqueue_get_fd!", ridx );
+       return -1;
+       }
+    return kqrevents[ridx].ident;
+    }
+
+#else /* HAVE_KQUEUE */
+
+
+# ifdef HAVE_DEVPOLL
+
+static int maxdpevents;
+static struct pollfd* dpevents;
+static int ndpevents;
+static struct pollfd* dprevents;
+static int* dp_rfdidx;
+static int dp;
+
+
+static int
+devpoll_init( int nf )
+    {
+    dp = open( "/dev/poll", O_RDWR );
+    if ( dp == -1 )
+       return -1;
+    (void) fcntl( dp, F_SETFD, 1 );
+    maxdpevents = nf * 2;
+    dpevents = (struct pollfd*) malloc( sizeof(struct pollfd) * maxdpevents );
+    dprevents = (struct pollfd*) malloc( sizeof(struct pollfd) * nf );
+    dp_rfdidx = (int*) malloc( sizeof(int) * nf );
+    if ( dpevents == (struct pollfd*) 0 || dprevents == (struct pollfd*) 0 ||
+        dp_rfdidx == (int*) 0 )
+       return -1;
+    (void) memset( dp_rfdidx, 0, sizeof(int) * nf );
+    return 0;
+    }
+
+
+static void
+devpoll_add_fd( int fd, int rw )
+    {
+    if ( ndpevents >= maxdpevents )
+       {
+       syslog( LOG_ERR, "too many fds in devpoll_add_fd!" );
+       return;
+       }
+    dpevents[ndpevents].fd = fd;
+    switch ( rw )
+       {
+       case FDW_READ: dpevents[ndpevents].events = POLLIN; break;
+       case FDW_WRITE: dpevents[ndpevents].events = POLLOUT; break;
+       default: break;
+       }
+    ++ndpevents;
+    }
+
+
+static void
+devpoll_del_fd( int fd )
+    {
+    if ( ndpevents >= maxdpevents )
+       {
+       syslog( LOG_ERR, "too many fds in devpoll_del_fd!" );
+       return;
+       }
+    dpevents[ndpevents].fd = fd;
+    dpevents[ndpevents].events = POLLREMOVE;
+    ++ndpevents;
+    }
+
+
+static int
+devpoll_watch( long timeout_msecs )
+    {
+    int i, r;
+    struct dvpoll dvp;
+
+    r = sizeof(struct pollfd) * ndpevents;
+    if ( r > 0 && write( dp, dpevents, r ) != r )
+       return -1;
+
+    ndpevents = 0;
+    dvp.dp_fds = dprevents;
+    dvp.dp_nfds = nfiles;
+    dvp.dp_timeout = (int) timeout_msecs;
+
+    r = ioctl( dp, DP_POLL, &dvp );
+    if ( r == -1 )
+       return -1;
+
+    for ( i = 0; i < r; ++i )
+       dp_rfdidx[dprevents[i].fd] = i;
+
+    return r;
+    }
+
+
+static int
+devpoll_check_fd( int fd )
+    {
+    int ridx = dp_rfdidx[fd];
+
+    if ( ridx < 0 || ridx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad ridx (%d) in devpoll_check_fd!", ridx );
+       return 0;
+       }
+    if ( ridx >= nreturned )
+       return 0;
+    if ( dprevents[ridx].fd != fd )
+       return 0;
+    if ( dprevents[ridx].revents & POLLERR )
+       return 0;
+    switch ( fd_rw[fd] )
+       {
+       case FDW_READ: return dprevents[ridx].revents & ( POLLIN | POLLHUP | POLLNVAL );
+       case FDW_WRITE: return dprevents[ridx].revents & ( POLLOUT | POLLHUP | POLLNVAL );
+       default: return 0;
+       }
+    }
+
+
+static int
+devpoll_get_fd( int ridx )
+    {
+    if ( ridx < 0 || ridx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad ridx (%d) in devpoll_get_fd!", ridx );
+       return -1;
+       }
+    return dprevents[ridx].fd;
+    }
+
+
+# else /* HAVE_DEVPOLL */
+
+
+#  ifdef HAVE_POLL
+
+static struct pollfd* pollfds;
+static int npoll_fds;
+static int* poll_fdidx;
+static int* poll_rfdidx;
+
+
+static int
+poll_init( int nf )
+    {
+    int i;
+
+    pollfds = (struct pollfd*) malloc( sizeof(struct pollfd) * nf );
+    poll_fdidx = (int*) malloc( sizeof(int) * nf );
+    poll_rfdidx = (int*) malloc( sizeof(int) * nf );
+    if ( pollfds == (struct pollfd*) 0 || poll_fdidx == (int*) 0 ||
+        poll_rfdidx == (int*) 0 )
+       return -1;
+    for ( i = 0; i < nf; ++i )
+       pollfds[i].fd = poll_fdidx[i] = -1;
+    return 0;
+    }
+
+
+static void
+poll_add_fd( int fd, int rw )
+    {
+    if ( npoll_fds >= nfiles )
+       {
+       syslog( LOG_ERR, "too many fds in poll_add_fd!" );
+       return;
+       }
+    pollfds[npoll_fds].fd = fd;
+    switch ( rw )
+       {
+       case FDW_READ: pollfds[npoll_fds].events = POLLIN; break;
+       case FDW_WRITE: pollfds[npoll_fds].events = POLLOUT; break;
+       default: break;
+       }
+    poll_fdidx[fd] = npoll_fds;
+    ++npoll_fds;
+    }
+
+
+static void
+poll_del_fd( int fd )
+    {
+    int idx = poll_fdidx[fd];
+
+    if ( idx < 0 || idx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad idx (%d) in poll_del_fd!", idx );
+       return;
+       }
+    --npoll_fds;
+    pollfds[idx] = pollfds[npoll_fds];
+    poll_fdidx[pollfds[idx].fd] = idx;
+    pollfds[npoll_fds].fd = -1;
+    poll_fdidx[fd] = -1;
+    }
+
+
+static int
+poll_watch( long timeout_msecs )
+    {
+    int r, ridx, i;
+
+    r = poll( pollfds, npoll_fds, (int) timeout_msecs );
+    if ( r <= 0 )
+       return r;
+
+    ridx = 0;
+    for ( i = 0; i < npoll_fds; ++i )
+       if ( pollfds[i].revents &
+            ( POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL ) )
+           {
+           poll_rfdidx[ridx++] = pollfds[i].fd;
+           if ( ridx == r )
+               break;
+           }
+
+    return ridx;       /* should be equal to r */
+    }
+
+
+static int
+poll_check_fd( int fd )
+    {
+    int fdidx = poll_fdidx[fd];
+
+    if ( fdidx < 0 || fdidx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad fdidx (%d) in poll_check_fd!", fdidx );
+       return 0;
+       }
+    if ( pollfds[fdidx].revents & POLLERR )
+       return 0;
+    switch ( fd_rw[fd] )
+       {
+       case FDW_READ: return pollfds[fdidx].revents & ( POLLIN | POLLHUP | POLLNVAL );
+       case FDW_WRITE: return pollfds[fdidx].revents & ( POLLOUT | POLLHUP | POLLNVAL );
+       default: return 0;
+       }
+    }
+
+
+static int
+poll_get_fd( int ridx )
+    {
+    if ( ridx < 0 || ridx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad ridx (%d) in poll_get_fd!", ridx );
+       return -1;
+       }
+    return poll_rfdidx[ridx];
+    }
+
+#  else /* HAVE_POLL */
+
+
+#   ifdef HAVE_SELECT
+
+static fd_set master_rfdset;
+static fd_set master_wfdset;
+static fd_set working_rfdset;
+static fd_set working_wfdset;
+static int* select_fds;
+static int* select_fdidx;
+static int* select_rfdidx;
+static int nselect_fds;
+static int maxfd;
+static int maxfd_changed;
+
+
+static int
+select_init( int nf )
+    {
+    int i;
+
+    FD_ZERO( &master_rfdset );
+    FD_ZERO( &master_wfdset );
+    select_fds = (int*) malloc( sizeof(int) * nf );
+    select_fdidx = (int*) malloc( sizeof(int) * nf );
+    select_rfdidx = (int*) malloc( sizeof(int) * nf );
+    if ( select_fds == (int*) 0 || select_fdidx == (int*) 0 ||
+        select_rfdidx == (int*) 0 )
+       return -1;
+    nselect_fds = 0;
+    maxfd = -1;
+    maxfd_changed = 0;
+    for ( i = 0; i < nf; ++i )
+       select_fds[i] = select_fdidx[i] = -1;
+    return 0;
+    }
+
+
+static void
+select_add_fd( int fd, int rw )
+    {
+    if ( nselect_fds >= nfiles )
+       {
+       syslog( LOG_ERR, "too many fds in select_add_fd!" );
+       return;
+       }
+    select_fds[nselect_fds] = fd;
+    switch ( rw )
+       {
+       case FDW_READ: FD_SET( fd, &master_rfdset ); break;
+       case FDW_WRITE: FD_SET( fd, &master_wfdset ); break;
+       default: break;
+       }
+    if ( fd > maxfd )
+       maxfd = fd;
+    select_fdidx[fd] = nselect_fds;
+    ++nselect_fds;
+    }
+
+
+static void
+select_del_fd( int fd )
+    {
+    int idx = select_fdidx[fd];
+
+    if ( idx < 0 || idx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad idx (%d) in select_del_fd!", idx );
+       return;
+       }
+
+    --nselect_fds;
+    select_fds[idx] = select_fds[nselect_fds];
+    select_fdidx[select_fds[idx]] = idx;
+    select_fds[nselect_fds] = -1;
+    select_fdidx[fd] = -1;
+
+    FD_CLR( fd, &master_rfdset );
+    FD_CLR( fd, &master_wfdset );
+
+    if ( fd >= maxfd )
+       maxfd_changed = 1;
+    }
+
+
+static int
+select_get_maxfd( void )
+    {
+    if ( maxfd_changed )
+       {
+       int i;
+       maxfd = -1;
+       for ( i = 0; i < nselect_fds; ++i )
+           if ( select_fds[i] > maxfd )
+               maxfd = select_fds[i];
+       maxfd_changed = 0;
+       }
+    return maxfd;
+    }
+
+
+static int
+select_watch( long timeout_msecs )
+    {
+    int mfd;
+    int r, idx, ridx;
+
+    working_rfdset = master_rfdset;
+    working_wfdset = master_wfdset;
+    mfd = select_get_maxfd();
+    if ( timeout_msecs == INFTIM )
+       r = select(
+           mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0,
+           (struct timeval*) 0 );
+    else
+       {
+       struct timeval timeout;
+       timeout.tv_sec = timeout_msecs / 1000L;
+       timeout.tv_usec = ( timeout_msecs % 1000L ) * 1000L;
+       r = select(
+          mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0, &timeout );
+       }
+    if ( r <= 0 )
+       return r;
+
+    ridx = 0;
+    for ( idx = 0; idx < nselect_fds; ++idx )
+       if ( select_check_fd( select_fds[idx] ) )
+           {
+           select_rfdidx[ridx++] = select_fds[idx];
+           if ( ridx == r )
+               break;
+           }
+
+    return ridx;       /* should be equal to r */
+    }
+
+
+static int
+select_check_fd( int fd )
+    {
+    switch ( fd_rw[fd] )
+       {
+       case FDW_READ: return FD_ISSET( fd, &working_rfdset );
+       case FDW_WRITE: return FD_ISSET( fd, &working_wfdset );
+       default: return 0;
+       }
+    }
+
+
+static int
+select_get_fd( int ridx )
+    {
+    if ( ridx < 0 || ridx >= nfiles )
+       {
+       syslog( LOG_ERR, "bad ridx (%d) in select_get_fd!", ridx );
+       return -1;
+       }
+    return select_rfdidx[ridx];
+    }
+
+#   endif /* HAVE_SELECT */
+
+#  endif /* HAVE_POLL */
+
+# endif /* HAVE_DEVPOLL */
+
+#endif /* HAVE_KQUEUE */
diff --git a/fdwatch.h b/fdwatch.h
new file mode 100644 (file)
index 0000000..96984cd
--- /dev/null
+++ b/fdwatch.h
@@ -0,0 +1,85 @@
+/* fdwatch.h - header file for fdwatch package
+**
+** This package abstracts the use of the select()/poll()/kqueue()
+** system calls.  The basic function of these calls is to watch a set
+** of file descriptors for activity.  select() originated in the BSD world,
+** while poll() came from SysV land, and their interfaces are somewhat
+** different.  fdwatch lets you write your code to a single interface,
+** with the portability differences hidden inside the package.
+**
+** Usage is fairly simple.  Call fdwatch_get_nfiles() to initialize
+** the package and find out how many fine descriptors are available.
+** Then each time through your main loop, call fdwatch_clear(), then
+** fdwatch_add_fd() for each of the descriptors you want to watch,
+** then call fdwatch() to actually perform the watch.  After it returns
+** you can check which descriptors are ready via fdwatch_check_fd().
+**
+** If your descriptor set hasn't changed from the last time through
+** the loop, you can skip calling fdwatch_clear() and fdwatch_add_fd()
+** to save a little CPU time.
+**
+**
+** Copyright © 1999 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _FDWATCH_H_
+#define _FDWATCH_H_
+
+#define FDW_READ 0
+#define FDW_WRITE 1
+
+#ifndef INFTIM
+#define INFTIM -1
+#endif /* INFTIM */
+
+/* Figure out how many file descriptors the system allows, and
+** initialize the fdwatch data structures.  Returns -1 on failure.
+*/
+int fdwatch_get_nfiles( void );
+
+/* Add a descriptor to the watch list.  rw is either FDW_READ or FDW_WRITE.  */
+void fdwatch_add_fd( int fd, void* client_data, int rw );
+
+/* Delete a descriptor from the watch list. */
+void fdwatch_del_fd( int fd );
+
+/* Do the watch.  Return value is the number of descriptors that are ready,
+** or 0 if the timeout expired, or -1 on errors.  A timeout of INFTIM means
+** wait indefinitely.
+*/
+int fdwatch( long timeout_msecs );
+
+/* Check if a descriptor was ready. */
+int fdwatch_check_fd( int fd );
+
+/* Get the client data for the next returned event.  Returns -1 when there
+** are no more events.
+*/
+void* fdwatch_get_next_client_data( void );
+
+/* Generate debugging statistics syslog message. */
+void fdwatch_logstats( long secs );
+
+#endif /* _FDWATCH_H_ */
diff --git a/fdwatch.o b/fdwatch.o
new file mode 100644 (file)
index 0000000..8c533c0
Binary files /dev/null and b/fdwatch.o differ
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..9131592
--- /dev/null
@@ -0,0 +1,14 @@
+<HTML>
+<HEAD><TITLE>thttpd is running</TITLE></HEAD>
+<BODY BGCOLOR="#99cc99" TEXT="#000000" LINK="#2020ff" VLINK="#4040cc">
+
+<H3>thttpd is running</H3>
+
+<P>
+Looks like you got it working.  Congrats.
+
+<P>
+Here's a link to the <A HREF="http://www.acme.com/software/thttpd/">thttpd web pages</A>.
+
+</BODY>
+</HTML>
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..ebc6691
--- /dev/null
@@ -0,0 +1,250 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/libhttpd.c b/libhttpd.c
new file mode 100644 (file)
index 0000000..c6b1622
--- /dev/null
@@ -0,0 +1,4279 @@
+/* libhttpd.c - HTTP protocol library
+**
+** Copyright © 1995,1998,1999,2000,2001,2015 by
+** Jef Poskanzer <jef@mail.acme.com>. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+
+#include "config.h"
+#include "version.h"
+
+#ifdef SHOW_SERVER_VERSION
+#define EXPOSED_SERVER_SOFTWARE SERVER_SOFTWARE
+#else /* SHOW_SERVER_VERSION */
+#define EXPOSED_SERVER_SOFTWARE "thttpd"
+#endif /* SHOW_SERVER_VERSION */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif /* HAVE_MEMORY_H */
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#ifdef HAVE_OSRELDATE_H
+#include <osreldate.h>
+#endif /* HAVE_OSRELDATE_H */
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#include "libhttpd.h"
+#include "mmc.h"
+#include "timers.h"
+#include "match.h"
+#include "tdate_parse.h"
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifndef HAVE_INT64T
+typedef long long int64_t;
+#endif
+
+#ifndef HAVE_SOCKLENT
+typedef int socklen_t;
+#endif
+
+#ifdef __CYGWIN__
+#define timezone  _timezone
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/* Forwards. */
+static void check_options( void );
+static void free_httpd_server( httpd_server* hs );
+static int initialize_listen_socket( httpd_sockaddr* saP );
+static void add_response( httpd_conn* hc, char* str );
+static void send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, off_t length, time_t mod );
+static void send_response( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg );
+static void send_response_tail( httpd_conn* hc );
+static void defang( char* str, char* dfstr, int dfsize );
+#ifdef ERR_DIR
+static int send_err_file( httpd_conn* hc, int status, char* title, char* extraheads, char* filename );
+#endif /* ERR_DIR */
+#ifdef AUTH_FILE
+static void send_authenticate( httpd_conn* hc, char* realm );
+static int b64_decode( const char* str, unsigned char* space, int size );
+static int auth_check( httpd_conn* hc, char* dirname  );
+static int auth_check2( httpd_conn* hc, char* dirname  );
+#endif /* AUTH_FILE */
+static void send_dirredirect( httpd_conn* hc );
+static int hexit( char c );
+static void strdecode( char* to, char* from );
+#ifdef GENERATE_INDEXES
+static void strencode( char* to, int tosize, char* from );
+#endif /* GENERATE_INDEXES */
+#ifdef TILDE_MAP_1
+static int tilde_map_1( httpd_conn* hc );
+#endif /* TILDE_MAP_1 */
+#ifdef TILDE_MAP_2
+static int tilde_map_2( httpd_conn* hc );
+#endif /* TILDE_MAP_2 */
+static int vhost_map( httpd_conn* hc );
+static char* expand_symlinks( char* path, char** restP, int no_symlink_check, int tildemapped );
+static char* bufgets( httpd_conn* hc );
+static void de_dotdot( char* file );
+static void init_mime( void );
+static void figure_mime( httpd_conn* hc );
+#ifdef CGI_TIMELIMIT
+static void cgi_kill2( ClientData client_data, struct timeval* nowP );
+static void cgi_kill( ClientData client_data, struct timeval* nowP );
+#endif /* CGI_TIMELIMIT */
+#ifdef GENERATE_INDEXES
+static int ls( httpd_conn* hc );
+#endif /* GENERATE_INDEXES */
+static char* build_env( char* fmt, char* arg );
+#ifdef SERVER_NAME_LIST
+static char* hostname_map( char* hostname );
+#endif /* SERVER_NAME_LIST */
+static char** make_envp( httpd_conn* hc );
+static char** make_argp( httpd_conn* hc );
+static void cgi_interpose_input( httpd_conn* hc, int wfd );
+static void post_post_garbage_hack( httpd_conn* hc );
+static void cgi_interpose_output( httpd_conn* hc, int rfd );
+static void cgi_child( httpd_conn* hc );
+static int cgi( httpd_conn* hc );
+static int really_start_request( httpd_conn* hc, struct timeval* nowP );
+static void make_log_entry( httpd_conn* hc, struct timeval* nowP );
+static int check_referrer( httpd_conn* hc );
+static int really_check_referrer( httpd_conn* hc );
+static int sockaddr_check( httpd_sockaddr* saP );
+static size_t sockaddr_len( httpd_sockaddr* saP );
+static int my_snprintf( char* str, size_t size, const char* format, ... );
+#ifndef HAVE_ATOLL
+static long long atoll( const char* str );
+#endif /* HAVE_ATOLL */
+
+
+/* This global keeps track of whether we are in the main process or a
+** sub-process.  The reason is that httpd_write_response() can get called
+** in either context; when it is called from the main process it must use
+** non-blocking I/O to avoid stalling the server, but when it is called
+** from a sub-process it wants to use blocking I/O so that the whole
+** response definitely gets written.  So, it checks this variable.  A bit
+** of a hack but it seems to do the right thing.
+*/
+static int sub_process = 0;
+
+
+static void
+check_options( void )
+    {
+#if defined(TILDE_MAP_1) && defined(TILDE_MAP_2)
+    syslog( LOG_CRIT, "both TILDE_MAP_1 and TILDE_MAP_2 are defined" );
+    exit( 1 );
+#endif /* both */
+    }
+
+
+static void
+free_httpd_server( httpd_server* hs )
+    {
+    if ( hs->binding_hostname != (char*) 0 )
+       free( (void*) hs->binding_hostname );
+    if ( hs->cwd != (char*) 0 )
+       free( (void*) hs->cwd );
+    if ( hs->cgi_pattern != (char*) 0 )
+       free( (void*) hs->cgi_pattern );
+    if ( hs->charset != (char*) 0 )
+       free( (void*) hs->charset );
+    if ( hs->p3p != (char*) 0 )
+       free( (void*) hs->p3p );
+    if ( hs->url_pattern != (char*) 0 )
+       free( (void*) hs->url_pattern );
+    if ( hs->local_pattern != (char*) 0 )
+       free( (void*) hs->local_pattern );
+    free( (void*) hs );
+    }
+
+
+httpd_server*
+httpd_initialize(
+    char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P,
+    unsigned short port, char* cgi_pattern, int cgi_limit, char* charset,
+    char* p3p, int max_age, char* cwd, int no_log, FILE* logfp,
+    int no_symlink_check, int vhost, int global_passwd, char* url_pattern,
+    char* local_pattern, int no_empty_referrers )
+    {
+    httpd_server* hs;
+    static char ghnbuf[256];
+    char* cp;
+
+    check_options();
+
+    hs = NEW( httpd_server, 1 );
+    if ( hs == (httpd_server*) 0 )
+       {
+       syslog( LOG_CRIT, "out of memory allocating an httpd_server" );
+       return (httpd_server*) 0;
+       }
+
+    if ( hostname != (char*) 0 )
+       {
+       hs->binding_hostname = strdup( hostname );
+       if ( hs->binding_hostname == (char*) 0 )
+           {
+           syslog( LOG_CRIT, "out of memory copying hostname" );
+           return (httpd_server*) 0;
+           }
+       hs->server_hostname = hs->binding_hostname;
+       }
+    else
+       {
+       hs->binding_hostname = (char*) 0;
+       hs->server_hostname = (char*) 0;
+       if ( gethostname( ghnbuf, sizeof(ghnbuf) ) < 0 )
+           ghnbuf[0] = '\0';
+#ifdef SERVER_NAME_LIST
+       if ( ghnbuf[0] != '\0' )
+           hs->server_hostname = hostname_map( ghnbuf );
+#endif /* SERVER_NAME_LIST */
+       if ( hs->server_hostname == (char*) 0 )
+           {
+#ifdef SERVER_NAME
+           hs->server_hostname = SERVER_NAME;
+#else /* SERVER_NAME */
+           if ( ghnbuf[0] != '\0' )
+               hs->server_hostname = ghnbuf;
+#endif /* SERVER_NAME */
+           }
+       }
+
+    hs->port = port;
+    if ( cgi_pattern == (char*) 0 )
+       hs->cgi_pattern = (char*) 0;
+    else
+       {
+       /* Nuke any leading slashes. */
+       if ( cgi_pattern[0] == '/' )
+           ++cgi_pattern;
+       hs->cgi_pattern = strdup( cgi_pattern );
+       if ( hs->cgi_pattern == (char*) 0 )
+           {
+           syslog( LOG_CRIT, "out of memory copying cgi_pattern" );
+           return (httpd_server*) 0;
+           }
+       /* Nuke any leading slashes in the cgi pattern. */
+       while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 )
+           (void) ol_strcpy( cp + 1, cp + 2 );
+       }
+    hs->cgi_limit = cgi_limit;
+    hs->cgi_count = 0;
+    hs->charset = strdup( charset );
+    hs->p3p = strdup( p3p );
+    hs->max_age = max_age;
+    hs->cwd = strdup( cwd );
+    if ( hs->cwd == (char*) 0 )
+       {
+       syslog( LOG_CRIT, "out of memory copying cwd" );
+       return (httpd_server*) 0;
+       }
+    if ( url_pattern == (char*) 0 )
+       hs->url_pattern = (char*) 0;
+    else
+       {
+       hs->url_pattern = strdup( url_pattern );
+       if ( hs->url_pattern == (char*) 0 )
+           {
+           syslog( LOG_CRIT, "out of memory copying url_pattern" );
+           return (httpd_server*) 0;
+           }
+       }
+    if ( local_pattern == (char*) 0 )
+       hs->local_pattern = (char*) 0;
+    else
+       {
+       hs->local_pattern = strdup( local_pattern );
+       if ( hs->local_pattern == (char*) 0 )
+           {
+           syslog( LOG_CRIT, "out of memory copying local_pattern" );
+           return (httpd_server*) 0;
+           }
+       }
+    hs->no_log = no_log;
+    hs->logfp = (FILE*) 0;
+    httpd_set_logfp( hs, logfp );
+    hs->no_symlink_check = no_symlink_check;
+    hs->vhost = vhost;
+    hs->global_passwd = global_passwd;
+    hs->no_empty_referrers = no_empty_referrers;
+
+    /* Initialize listen sockets.  Try v6 first because of a Linux peculiarity;
+    ** like some other systems, it has magical v6 sockets that also listen for
+    ** v4, but in Linux if you bind a v4 socket first then the v6 bind fails.
+    */
+    if ( sa6P == (httpd_sockaddr*) 0 )
+       hs->listen6_fd = -1;
+    else
+       hs->listen6_fd = initialize_listen_socket( sa6P );
+    if ( sa4P == (httpd_sockaddr*) 0 )
+       hs->listen4_fd = -1;
+    else
+       hs->listen4_fd = initialize_listen_socket( sa4P );
+    /* If we didn't get any valid sockets, fail. */
+    if ( hs->listen4_fd == -1 && hs->listen6_fd == -1 )
+       {
+       free_httpd_server( hs );
+       return (httpd_server*) 0;
+       }
+
+    init_mime();
+
+    /* Done initializing. */
+    if ( hs->binding_hostname == (char*) 0 )
+       syslog(
+           LOG_NOTICE, "%.80s starting on port %d", SERVER_SOFTWARE,
+           (int) hs->port );
+    else
+       syslog(
+           LOG_NOTICE, "%.80s starting on %.80s, port %d", SERVER_SOFTWARE,
+           httpd_ntoa( hs->listen4_fd != -1 ? sa4P : sa6P ),
+           (int) hs->port );
+    return hs;
+    }
+
+
+static int
+initialize_listen_socket( httpd_sockaddr* saP )
+    {
+    int listen_fd;
+    int on, flags;
+
+    /* Check sockaddr. */
+    if ( ! sockaddr_check( saP ) )
+       {
+       syslog( LOG_CRIT, "unknown sockaddr family on listen socket" );
+       return -1;
+       }
+
+    /* Create socket. */
+    listen_fd = socket( saP->sa.sa_family, SOCK_STREAM, 0 );
+    if ( listen_fd < 0 )
+       {
+       syslog( LOG_CRIT, "socket %.80s - %m", httpd_ntoa( saP ) );
+       return -1;
+       }
+    (void) fcntl( listen_fd, F_SETFD, 1 );
+
+    /* Allow reuse of local addresses. */
+    on = 1;
+    if ( setsockopt(
+            listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &on,
+            sizeof(on) ) < 0 )
+       syslog( LOG_CRIT, "setsockopt SO_REUSEADDR - %m" );
+
+    /* Bind to it. */
+    if ( bind( listen_fd, &saP->sa, sockaddr_len( saP ) ) < 0 )
+       {
+       syslog(
+           LOG_CRIT, "bind %.80s - %m", httpd_ntoa( saP ) );
+       (void) close( listen_fd );
+       return -1;
+       }
+
+    /* Set the listen file descriptor to no-delay / non-blocking mode. */
+    flags = fcntl( listen_fd, F_GETFL, 0 );
+    if ( flags == -1 )
+       {
+       syslog( LOG_CRIT, "fcntl F_GETFL - %m" );
+       (void) close( listen_fd );
+       return -1;
+       }
+    if ( fcntl( listen_fd, F_SETFL, flags | O_NDELAY ) < 0 )
+       {
+       syslog( LOG_CRIT, "fcntl O_NDELAY - %m" );
+       (void) close( listen_fd );
+       return -1;
+       }
+
+    /* Start a listen going. */
+    if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 )
+       {
+       syslog( LOG_CRIT, "listen - %m" );
+       (void) close( listen_fd );
+       return -1;
+       }
+
+    /* Use accept filtering, if available. */
+#ifdef SO_ACCEPTFILTER
+    {
+#if ( __FreeBSD_version >= 411000 )
+#define ACCEPT_FILTER_NAME "httpready"
+#else
+#define ACCEPT_FILTER_NAME "dataready"
+#endif
+    struct accept_filter_arg af;
+    (void) bzero( &af, sizeof(af) );
+    (void) strcpy( af.af_name, ACCEPT_FILTER_NAME );
+    (void) setsockopt(
+       listen_fd, SOL_SOCKET, SO_ACCEPTFILTER, (char*) &af, sizeof(af) );
+    }
+#endif /* SO_ACCEPTFILTER */
+
+    return listen_fd;
+    }
+
+
+void
+httpd_set_logfp( httpd_server* hs, FILE* logfp )
+    {
+    if ( hs->logfp != (FILE*) 0 )
+       (void) fclose( hs->logfp );
+    hs->logfp = logfp;
+    }
+
+
+void
+httpd_terminate( httpd_server* hs )
+    {
+    httpd_unlisten( hs );
+    if ( hs->logfp != (FILE*) 0 )
+       (void) fclose( hs->logfp );
+    free_httpd_server( hs );
+    }
+
+
+void
+httpd_unlisten( httpd_server* hs )
+    {
+    if ( hs->listen4_fd != -1 )
+       {
+       (void) close( hs->listen4_fd );
+       hs->listen4_fd = -1;
+       }
+    if ( hs->listen6_fd != -1 )
+       {
+       (void) close( hs->listen6_fd );
+       hs->listen6_fd = -1;
+       }
+    }
+
+
+/* Conditional macro to allow two alternate forms for use in the built-in
+** error pages.  If EXPLICIT_ERROR_PAGES is defined, the second and more
+** explicit error form is used; otherwise, the first and more generic
+** form is used.
+*/
+#ifdef EXPLICIT_ERROR_PAGES
+#define ERROR_FORM(a,b) b
+#else /* EXPLICIT_ERROR_PAGES */
+#define ERROR_FORM(a,b) a
+#endif /* EXPLICIT_ERROR_PAGES */
+
+
+static char* ok200title = "OK";
+static char* ok206title = "Partial Content";
+
+static char* err302title = "Found";
+static char* err302form = "The actual URL is '%.80s'.\n";
+
+static char* err304title = "Not Modified";
+
+char* httpd_err400title = "Bad Request";
+char* httpd_err400form =
+    "Your request has bad syntax or is inherently impossible to satisfy.\n";
+
+#ifdef AUTH_FILE
+static char* err401title = "Unauthorized";
+static char* err401form =
+    "Authorization required for the URL '%.80s'.\n";
+#endif /* AUTH_FILE */
+
+static char* err403title = "Forbidden";
+#ifndef EXPLICIT_ERROR_PAGES
+static char* err403form =
+    "You do not have permission to get URL '%.80s' from this server.\n";
+#endif /* !EXPLICIT_ERROR_PAGES */
+
+static char* err404title = "Not Found";
+static char* err404form =
+    "The requested URL '%.80s' was not found on this server.\n";
+
+char* httpd_err408title = "Request Timeout";
+char* httpd_err408form =
+    "No request appeared within a reasonable time period.\n";
+
+static char* err451title = "Unavailable For Legal Reasons";
+static char* err451form =
+    "You do not have legal permission to get URL '%.80s' from this server.\n";
+
+static char* err500title = "Internal Error";
+static char* err500form =
+    "There was an unusual problem serving the requested URL '%.80s'.\n";
+
+static char* err501title = "Not Implemented";
+static char* err501form =
+    "The requested method '%.80s' is not implemented by this server.\n";
+
+char* httpd_err503title = "Service Temporarily Overloaded";
+char* httpd_err503form =
+    "The requested URL '%.80s' is temporarily overloaded.  Please try again later.\n";
+
+
+/* Append a string to the buffer waiting to be sent as response. */
+static void
+add_response( httpd_conn* hc, char* str )
+    {
+    size_t len;
+
+    len = strlen( str );
+    httpd_realloc_str( &hc->response, &hc->maxresponse, hc->responselen + len );
+    (void) memmove( &(hc->response[hc->responselen]), str, len );
+    hc->responselen += len;
+    }
+
+/* Send the buffered response. */
+void
+httpd_write_response( httpd_conn* hc )
+    {
+    /* If we are in a sub-process, turn off no-delay mode. */
+    if ( sub_process )
+       httpd_clear_ndelay( hc->conn_fd );
+    /* Send the response, if necessary. */
+    if ( hc->responselen > 0 )
+       {
+       (void) httpd_write_fully( hc->conn_fd, hc->response, hc->responselen );
+       hc->responselen = 0;
+       }
+    }
+
+
+/* Set no-delay / non-blocking mode on a socket. */
+void
+httpd_set_ndelay( int fd )
+    {
+    int flags, newflags;
+
+    flags = fcntl( fd, F_GETFL, 0 );
+    if ( flags != -1 )
+       {
+       newflags = flags | (int) O_NDELAY;
+       if ( newflags != flags )
+           (void) fcntl( fd, F_SETFL, newflags );
+       }
+    }
+
+
+/* Clear no-delay / non-blocking mode on a socket. */
+void
+httpd_clear_ndelay( int fd )
+    {
+    int flags, newflags;
+
+    flags = fcntl( fd, F_GETFL, 0 );
+    if ( flags != -1 )
+       {
+       newflags = flags & ~ (int) O_NDELAY;
+       if ( newflags != flags )
+           (void) fcntl( fd, F_SETFL, newflags );
+       }
+    }
+
+
+static void
+send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, off_t length, time_t mod )
+    {
+    time_t now, expires;
+    const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
+    char nowbuf[100];
+    char modbuf[100];
+    char expbuf[100];
+    char fixed_type[500];
+    char buf[1000];
+    int partial_content;
+    int s100;
+
+    hc->status = status;
+    hc->bytes_to_send = length;
+    if ( hc->mime_flag )
+       {
+       if ( status == 200 && hc->got_range &&
+            ( hc->last_byte_index >= hc->first_byte_index ) &&
+            ( ( hc->last_byte_index != length - 1 ) ||
+              ( hc->first_byte_index != 0 ) ) &&
+            ( hc->range_if == (time_t) -1 ||
+              hc->range_if == hc->sb.st_mtime ) )
+           {
+           partial_content = 1;
+           hc->status = status = 206;
+           title = ok206title;
+           }
+       else
+           {
+           partial_content = 0;
+           hc->got_range = 0;
+           }
+
+       now = time( (time_t*) 0 );
+       if ( mod == (time_t) 0 )
+           mod = now;
+       (void) strftime( nowbuf, sizeof(nowbuf), rfc1123fmt, gmtime( &now ) );
+       (void) strftime( modbuf, sizeof(modbuf), rfc1123fmt, gmtime( &mod ) );
+       (void) my_snprintf(
+           fixed_type, sizeof(fixed_type), type, hc->hs->charset );
+       (void) my_snprintf( buf, sizeof(buf),
+           "%.20s %d %s\015\012Server: %s\015\012Content-Type: %s\015\012Date: %s\015\012Last-Modified: %s\015\012Accept-Ranges: bytes\015\012Connection: close\015\012",
+           hc->protocol, status, title, EXPOSED_SERVER_SOFTWARE, fixed_type,
+           nowbuf, modbuf );
+       add_response( hc, buf );
+       s100 = status / 100;
+       if ( s100 != 2 && s100 != 3 )
+           {
+           (void) my_snprintf( buf, sizeof(buf),
+               "Cache-Control: no-cache,no-store\015\012" );
+           add_response( hc, buf );
+           }
+       if ( encodings[0] != '\0' )
+           {
+           (void) my_snprintf( buf, sizeof(buf),
+               "Content-Encoding: %s\015\012", encodings );
+           add_response( hc, buf );
+           }
+       if ( partial_content )
+           {
+           (void) my_snprintf( buf, sizeof(buf),
+               "Content-Range: bytes %lld-%lld/%lld\015\012Content-Length: %lld\015\012",
+               (long long) hc->first_byte_index,
+               (long long) hc->last_byte_index,
+               (long long) length,
+               (long long) ( hc->last_byte_index - hc->first_byte_index + 1 ) );
+           add_response( hc, buf );
+           }
+       else if ( length >= 0 )
+           {
+           (void) my_snprintf( buf, sizeof(buf),
+               "Content-Length: %lld\015\012", (long long) length );
+           add_response( hc, buf );
+           }
+       if ( hc->hs->p3p[0] != '\0' )
+           {
+           (void) my_snprintf( buf, sizeof(buf), "P3P: %s\015\012", hc->hs->p3p );
+           add_response( hc, buf );
+           }
+       if ( hc->hs->max_age >= 0 )
+           {
+           expires = now + hc->hs->max_age;
+           (void) strftime(
+               expbuf, sizeof(expbuf), rfc1123fmt, gmtime( &expires ) );
+           (void) my_snprintf( buf, sizeof(buf),
+               "Cache-Control: max-age=%d\015\012Expires: %s\015\012",
+               hc->hs->max_age, expbuf );
+           add_response( hc, buf );
+           }
+       if ( extraheads[0] != '\0' )
+           add_response( hc, extraheads );
+       add_response( hc, "\015\012" );
+       }
+    }
+
+
+static int str_alloc_count = 0;
+static size_t str_alloc_size = 0;
+
+void
+httpd_realloc_str( char** strP, size_t* maxsizeP, size_t size )
+    {
+    if ( *maxsizeP == 0 )
+       {
+       *maxsizeP = MAX( 200, size + 100 );
+       *strP = NEW( char, *maxsizeP + 1 );
+       ++str_alloc_count;
+       str_alloc_size += *maxsizeP;
+       }
+    else if ( size > *maxsizeP )
+       {
+       str_alloc_size -= *maxsizeP;
+       *maxsizeP = MAX( *maxsizeP * 2, size * 5 / 4 );
+       *strP = RENEW( *strP, char, *maxsizeP + 1 );
+       str_alloc_size += *maxsizeP;
+       }
+    else
+       return;
+    if ( *strP == (char*) 0 )
+       {
+       syslog(
+           LOG_ERR, "out of memory reallocating a string to %ld bytes",
+           (long) *maxsizeP );
+       exit( 1 );
+       }
+    }
+
+
+static void
+send_response( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg )
+    {
+    char defanged_arg[1000], buf[2000];
+
+    send_mime(
+       hc, status, title, "", extraheads, "text/html; charset=%s", (off_t) -1,
+       (time_t) 0 );
+    (void) my_snprintf( buf, sizeof(buf), "\
+<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n\
+\n\
+<html>\n\
+\n\
+  <head>\n\
+    <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\n\
+    <title>%d %s</title>\n\
+  </head>\n\
+\n\
+  <body bgcolor=\"#cc9999\" text=\"#000000\" link=\"#2020ff\" vlink=\"#4040cc\">\n\
+\n\
+    <h2>%d %s</h2>\n",
+       status, title, status, title );
+    add_response( hc, buf );
+    defang( arg, defanged_arg, sizeof(defanged_arg) );
+    (void) my_snprintf( buf, sizeof(buf), form, defanged_arg );
+    add_response( hc, buf );
+    if ( match( "**MSIE**", hc->useragent ) )
+       {
+       int n;
+       add_response( hc, "<!--\n" );
+       for ( n = 0; n < 6; ++n )
+           add_response( hc, "Padding so that MSIE deigns to show this error instead of its own canned one.\n");
+       add_response( hc, "-->\n" );
+       }
+    send_response_tail( hc );
+    }
+
+
+static void
+send_response_tail( httpd_conn* hc )
+    {
+    char buf[1000];
+
+    (void) my_snprintf( buf, sizeof(buf), "\
+    <hr>\n\
+\n\
+    <address><a href=\"%s\">%s</a></address>\n\
+\n\
+  </body>\n\
+\n\
+</html>\n",
+       SERVER_ADDRESS, EXPOSED_SERVER_SOFTWARE );
+    add_response( hc, buf );
+    }
+
+
+static void
+defang( char* str, char* dfstr, int dfsize )
+    {
+    char* cp1;
+    char* cp2;
+
+    for ( cp1 = str, cp2 = dfstr;
+         *cp1 != '\0' && cp2 - dfstr < dfsize - 5;
+         ++cp1, ++cp2 )
+       {
+       switch ( *cp1 )
+           {
+           case '<':
+           *cp2++ = '&';
+           *cp2++ = 'l';
+           *cp2++ = 't';
+           *cp2 = ';';
+           break;
+           case '>':
+           *cp2++ = '&';
+           *cp2++ = 'g';
+           *cp2++ = 't';
+           *cp2 = ';';
+           break;
+           default:
+           *cp2 = *cp1;
+           break;
+           }
+       }
+    *cp2 = '\0';
+    }
+
+
+void
+httpd_send_err( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg )
+    {
+#ifdef ERR_DIR
+
+    char filename[1000];
+
+    /* Try virtual host error page. */
+    if ( hc->hs->vhost && hc->hostdir[0] != '\0' )
+       {
+       (void) my_snprintf( filename, sizeof(filename),
+           "%s/%s/err%d.html", hc->hostdir, ERR_DIR, status );
+       if ( send_err_file( hc, status, title, extraheads, filename ) )
+           return;
+       }
+
+    /* Try server-wide error page. */
+    (void) my_snprintf( filename, sizeof(filename),
+       "%s/err%d.html", ERR_DIR, status );
+    if ( send_err_file( hc, status, title, extraheads, filename ) )
+       return;
+
+    /* Fall back on built-in error page. */
+    send_response( hc, status, title, extraheads, form, arg );
+
+#else /* ERR_DIR */
+
+    send_response( hc, status, title, extraheads, form, arg );
+
+#endif /* ERR_DIR */
+    }
+
+
+#ifdef ERR_DIR
+static int
+send_err_file( httpd_conn* hc, int status, char* title, char* extraheads, char* filename )
+    {
+    FILE* fp;
+    char buf[1000];
+    size_t r;
+
+    fp = fopen( filename, "r" );
+    if ( fp == (FILE*) 0 )
+       return 0;
+    send_mime(
+       hc, status, title, "", extraheads, "text/html; charset=%s", (off_t) -1,
+       (time_t) 0 );
+    for (;;)
+       {
+       r = fread( buf, 1, sizeof(buf) - 1, fp );
+       if ( r == 0 )
+           break;
+       buf[r] = '\0';
+       add_response( hc, buf );
+       }
+    (void) fclose( fp );
+
+#ifdef ERR_APPEND_SERVER_INFO
+    send_response_tail( hc );
+#endif /* ERR_APPEND_SERVER_INFO */
+
+    return 1;
+    }
+#endif /* ERR_DIR */
+
+
+#ifdef AUTH_FILE
+
+static void
+send_authenticate( httpd_conn* hc, char* realm )
+    {
+    static char* header;
+    static size_t maxheader = 0;
+    static char headstr[] = "WWW-Authenticate: Basic realm=\"";
+
+    httpd_realloc_str(
+       &header, &maxheader, sizeof(headstr) + strlen( realm ) + 3 );
+    (void) my_snprintf( header, maxheader, "%s%s\"\015\012", headstr, realm );
+    httpd_send_err( hc, 401, err401title, header, err401form, hc->encodedurl );
+    /* If the request was a POST then there might still be data to be read,
+    ** so we need to do a lingering close.
+    */
+    if ( hc->method == METHOD_POST )
+       hc->should_linger = 1;
+    }
+
+
+/* Base-64 decoding.  This represents binary data as printable ASCII
+** characters.  Three 8-bit binary bytes are turned into four 6-bit
+** values, like so:
+**
+**   [11111111]  [22222222]  [33333333]
+**
+**   [111111] [112222] [222233] [333333]
+**
+** Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
+*/
+
+static int b64_decode_table[256] = {
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
+    52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
+    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
+    15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
+    -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
+    41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
+    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
+    };
+
+/* Do base-64 decoding on a string.  Ignore any non-base64 bytes.
+** Return the actual number of bytes generated.  The decoded size will
+** be at most 3/4 the size of the encoded, and may be smaller if there
+** are padding characters (blanks, newlines).
+*/
+static int
+b64_decode( const char* str, unsigned char* space, int size )
+    {
+    const char* cp;
+    int space_idx, phase;
+    int d, prev_d = 0;
+    unsigned char c;
+
+    space_idx = 0;
+    phase = 0;
+    for ( cp = str; *cp != '\0'; ++cp )
+       {
+       d = b64_decode_table[(int) ((unsigned char) *cp)];
+       if ( d != -1 )
+           {
+           switch ( phase )
+               {
+               case 0:
+               ++phase;
+               break;
+               case 1:
+               c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );
+               if ( space_idx < size )
+                   space[space_idx++] = c;
+               ++phase;
+               break;
+               case 2:
+               c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );
+               if ( space_idx < size )
+                   space[space_idx++] = c;
+               ++phase;
+               break;
+               case 3:
+               c = ( ( ( prev_d & 0x03 ) << 6 ) | d );
+               if ( space_idx < size )
+                   space[space_idx++] = c;
+               phase = 0;
+               break;
+               }
+           prev_d = d;
+           }
+       }
+    return space_idx;
+    }
+
+
+/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */
+static int
+auth_check( httpd_conn* hc, char* dirname  )
+    {
+    if ( hc->hs->global_passwd )
+       {
+       char* topdir;
+       if ( hc->hs->vhost && hc->hostdir[0] != '\0' )
+           topdir = hc->hostdir;
+       else
+           topdir = ".";
+       switch ( auth_check2( hc, topdir ) )
+           {
+           case -1:
+           return -1;
+           case 1:
+           return 1;
+           }
+       }
+    return auth_check2( hc, dirname );
+    }
+
+
+/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */
+static int
+auth_check2( httpd_conn* hc, char* dirname  )
+    {
+    static char* authpath;
+    static size_t maxauthpath = 0;
+    struct stat sb;
+    char authinfo[500];
+    char* authpass;
+    char* colon;
+    int l;
+    FILE* fp;
+    char line[500];
+    char* cryp;
+    static char* prevauthpath;
+    static size_t maxprevauthpath = 0;
+    static time_t prevmtime;
+    static char* prevuser;
+    static size_t maxprevuser = 0;
+    static char* prevcryp;
+    static size_t maxprevcryp = 0;
+
+    /* Construct auth filename. */
+    httpd_realloc_str(
+       &authpath, &maxauthpath, strlen( dirname ) + 1 + sizeof(AUTH_FILE) );
+    (void) my_snprintf( authpath, maxauthpath, "%s/%s", dirname, AUTH_FILE );
+
+    /* Does this directory have an auth file? */
+    if ( stat( authpath, &sb ) < 0 )
+       /* Nope, let the request go through. */
+       return 0;
+
+    /* Does this request contain basic authorization info? */
+    if ( hc->authorization[0] == '\0' ||
+        strncmp( hc->authorization, "Basic ", 6 ) != 0 )
+       {
+       /* Nope, return a 401 Unauthorized. */
+       send_authenticate( hc, dirname );
+       return -1;
+       }
+
+    /* Decode it. */
+    l = b64_decode(
+       &(hc->authorization[6]), (unsigned char*) authinfo,
+       sizeof(authinfo) - 1 );
+    authinfo[l] = '\0';
+    /* Split into user and password. */
+    authpass = strchr( authinfo, ':' );
+    if ( authpass == (char*) 0 )
+       {
+       /* No colon?  Bogus auth info. */
+       send_authenticate( hc, dirname );
+       return -1;
+       }
+    *authpass++ = '\0';
+    /* If there are more fields, cut them off. */
+    colon = strchr( authpass, ':' );
+    if ( colon != (char*) 0 )
+       *colon = '\0';
+
+    /* See if we have a cached entry and can use it. */
+    if ( maxprevauthpath != 0 &&
+        strcmp( authpath, prevauthpath ) == 0 &&
+        sb.st_mtime == prevmtime &&
+        strcmp( authinfo, prevuser ) == 0 )
+       {
+       /* Yes.  Check against the cached encrypted password. */
+       if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )
+           {
+           /* Ok! */
+           httpd_realloc_str(
+               &hc->remoteuser, &hc->maxremoteuser, strlen( authinfo ) );
+           (void) strcpy( hc->remoteuser, authinfo );
+           return 1;
+           }
+       else
+           {
+           /* No. */
+           send_authenticate( hc, dirname );
+           return -1;
+           }
+       }
+
+    /* Open the password file. */
+    fp = fopen( authpath, "r" );
+    if ( fp == (FILE*) 0 )
+       {
+       /* The file exists but we can't open it?  Disallow access. */
+       syslog(
+           LOG_ERR, "%.80s auth file %.80s could not be opened - %m",
+           httpd_ntoa( &hc->client_addr ), authpath );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "The requested URL '%.80s' is protected by an authentication file, but the authentication file cannot be opened.\n" ),
+           hc->encodedurl );
+       return -1;
+       }
+
+    /* Read it. */
+    while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
+       {
+       /* Nuke newline. */
+       l = strlen( line );
+       if ( line[l - 1] == '\n' )
+           line[l - 1] = '\0';
+       /* Split into user and encrypted password. */
+       cryp = strchr( line, ':' );
+       if ( cryp == (char*) 0 )
+           continue;
+       *cryp++ = '\0';
+       /* Is this the right user? */
+       if ( strcmp( line, authinfo ) == 0 )
+           {
+           /* Yes. */
+           (void) fclose( fp );
+           /* So is the password right? */
+           if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
+               {
+               /* Ok! */
+               httpd_realloc_str(
+                   &hc->remoteuser, &hc->maxremoteuser, strlen( line ) );
+               (void) strcpy( hc->remoteuser, line );
+               /* And cache this user's info for next time. */
+               httpd_realloc_str(
+                   &prevauthpath, &maxprevauthpath, strlen( authpath ) );
+               (void) strcpy( prevauthpath, authpath );
+               prevmtime = sb.st_mtime;
+               httpd_realloc_str(
+                   &prevuser, &maxprevuser, strlen( authinfo ) );
+               (void) strcpy( prevuser, authinfo );
+               httpd_realloc_str( &prevcryp, &maxprevcryp, strlen( cryp ) );
+               (void) strcpy( prevcryp, cryp );
+               return 1;
+               }
+           else
+               {
+               /* No. */
+               send_authenticate( hc, dirname );
+               return -1;
+               }
+           }
+       }
+
+    /* Didn't find that user.  Access denied. */
+    (void) fclose( fp );
+    send_authenticate( hc, dirname );
+    return -1;
+    }
+
+#endif /* AUTH_FILE */
+
+
+static void
+send_dirredirect( httpd_conn* hc )
+    {
+    static char* location;
+    static char* header;
+    static size_t maxlocation = 0, maxheader = 0;
+    static char headstr[] = "Location: ";
+
+    if ( hc->query[0] != '\0')
+       {
+       char* cp = strchr( hc->encodedurl, '?' );
+       if ( cp != (char*) 0 )  /* should always find it */
+           *cp = '\0';
+       httpd_realloc_str(
+           &location, &maxlocation,
+           strlen( hc->encodedurl ) + 2 + strlen( hc->query ) );
+       (void) my_snprintf( location, maxlocation,
+           "%s/?%s", hc->encodedurl, hc->query );
+       }
+    else
+       {
+       httpd_realloc_str(
+           &location, &maxlocation, strlen( hc->encodedurl ) + 1 );
+       (void) my_snprintf( location, maxlocation,
+           "%s/", hc->encodedurl );
+       }
+    httpd_realloc_str(
+       &header, &maxheader, sizeof(headstr) + strlen( location ) );
+    (void) my_snprintf( header, maxheader,
+       "%s%s\015\012", headstr, location );
+    send_response( hc, 302, err302title, header, err302form, location );
+    }
+
+
+char*
+httpd_method_str( int method )
+    {
+    switch ( method )
+       {
+       case METHOD_GET: return "GET";
+       case METHOD_HEAD: return "HEAD";
+       case METHOD_POST: return "POST";
+       case METHOD_PUT: return "PUT";
+       case METHOD_DELETE: return "DELETE";
+       case METHOD_TRACE: return "TRACE";
+       default: return "UNKNOWN";
+       }
+    }
+
+
+static int
+hexit( char c )
+    {
+    if ( c >= '0' && c <= '9' )
+       return c - '0';
+    if ( c >= 'a' && c <= 'f' )
+       return c - 'a' + 10;
+    if ( c >= 'A' && c <= 'F' )
+       return c - 'A' + 10;
+    return 0;           /* shouldn't happen, we're guarded by isxdigit() */
+    }
+
+
+/* Copies and decodes a string.  It's ok for from and to to be the
+** same string.
+*/
+static void
+strdecode( char* to, char* from )
+    {
+    for ( ; *from != '\0'; ++to, ++from )
+       {
+       if ( from[0] == '%' && isxdigit( from[1] ) && isxdigit( from[2] ) )
+           {
+           *to = hexit( from[1] ) * 16 + hexit( from[2] );
+           from += 2;
+           }
+       else
+           *to = *from;
+       }
+    *to = '\0';
+    }
+
+
+#ifdef GENERATE_INDEXES
+/* Copies and encodes a string. */
+static void
+strencode( char* to, int tosize, char* from )
+    {
+    int tolen;
+
+    for ( tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from )
+       {
+       if ( isalnum(*from) || strchr( "/_.-~", *from ) != (char*) 0 )
+           {
+           *to = *from;
+           ++to;
+           ++tolen;
+           }
+       else
+           {
+           (void) sprintf( to, "%%%02x", (int) *from & 0xff );
+           to += 3;
+           tolen += 3;
+           }
+       }
+    *to = '\0';
+    }
+#endif /* GENERATE_INDEXES */
+
+
+#ifdef TILDE_MAP_1
+/* Map a ~username/whatever URL into <prefix>/username. */
+static int
+tilde_map_1( httpd_conn* hc )
+    {
+    static char* temp;
+    static size_t maxtemp = 0;
+    int len;
+    static char* prefix = TILDE_MAP_1;
+
+    len = strlen( hc->expnfilename ) - 1;
+    httpd_realloc_str( &temp, &maxtemp, len );
+    (void) strcpy( temp, &hc->expnfilename[1] );
+    httpd_realloc_str(
+       &hc->expnfilename, &hc->maxexpnfilename, strlen( prefix ) + 1 + len );
+    (void) strcpy( hc->expnfilename, prefix );
+    if ( prefix[0] != '\0' )
+       (void) strcat( hc->expnfilename, "/" );
+    (void) strcat( hc->expnfilename, temp );
+    return 1;
+    }
+#endif /* TILDE_MAP_1 */
+
+#ifdef TILDE_MAP_2
+/* Map a ~username/whatever URL into <user's homedir>/<postfix>. */
+static int
+tilde_map_2( httpd_conn* hc )
+    {
+    static char* temp;
+    static size_t maxtemp = 0;
+    static char* postfix = TILDE_MAP_2;
+    char* cp;
+    struct passwd* pw;
+    char* alt;
+    char* rest;
+
+    /* Get the username. */
+    httpd_realloc_str( &temp, &maxtemp, strlen( hc->expnfilename ) - 1 );
+    (void) strcpy( temp, &hc->expnfilename[1] );
+    cp = strchr( temp, '/' );
+    if ( cp != (char*) 0 )
+       *cp++ = '\0';
+    else
+       cp = "";
+
+    /* Get the passwd entry. */
+    pw = getpwnam( temp );
+    if ( pw == (struct passwd*) 0 )
+       return 0;
+
+    /* Set up altdir. */
+    httpd_realloc_str(
+       &hc->altdir, &hc->maxaltdir,
+       strlen( pw->pw_dir ) + 1 + strlen( postfix ) );
+    (void) strcpy( hc->altdir, pw->pw_dir );
+    if ( postfix[0] != '\0' )
+       {
+       (void) strcat( hc->altdir, "/" );
+       (void) strcat( hc->altdir, postfix );
+       }
+    alt = expand_symlinks( hc->altdir, &rest, 0, 1 );
+    if ( rest[0] != '\0' )
+       return 0;
+    httpd_realloc_str( &hc->altdir, &hc->maxaltdir, strlen( alt ) );
+    (void) strcpy( hc->altdir, alt );
+
+    /* And the filename becomes altdir plus the post-~ part of the original. */
+    httpd_realloc_str(
+       &hc->expnfilename, &hc->maxexpnfilename,
+       strlen( hc->altdir ) + 1 + strlen( cp ) );
+    (void) my_snprintf( hc->expnfilename, hc->maxexpnfilename,
+       "%s/%s", hc->altdir, cp );
+
+    /* For this type of tilde mapping, we want to defeat vhost mapping. */
+    hc->tildemapped = 1;
+
+    return 1;
+    }
+#endif /* TILDE_MAP_2 */
+
+
+/* Virtual host mapping. */
+static int
+vhost_map( httpd_conn* hc )
+    {
+    httpd_sockaddr sa;
+    socklen_t sz;
+    static char* tempfilename;
+    static size_t maxtempfilename = 0;
+    char* cp1;
+    int len;
+#ifdef VHOST_DIRLEVELS
+    int i;
+    char* cp2;
+#endif /* VHOST_DIRLEVELS */
+
+    /* Figure out the virtual hostname. */
+    if ( hc->reqhost[0] != '\0' )
+       hc->hostname = hc->reqhost;
+    else if ( hc->hdrhost[0] != '\0' )
+       hc->hostname = hc->hdrhost;
+    else
+       {
+       sz = sizeof(sa);
+       if ( getsockname( hc->conn_fd, &sa.sa, &sz ) < 0 )
+           {
+           syslog( LOG_ERR, "getsockname - %m" );
+           return 0;
+           }
+       hc->hostname = httpd_ntoa( &sa );
+       }
+    /* Pound it to lower case. */
+    for ( cp1 = hc->hostname; *cp1 != '\0'; ++cp1 )
+       if ( isupper( *cp1 ) )
+           *cp1 = tolower( *cp1 );
+
+    if ( hc->tildemapped )
+       return 1;
+
+    /* Figure out the host directory. */
+#ifdef VHOST_DIRLEVELS
+    httpd_realloc_str(
+       &hc->hostdir, &hc->maxhostdir,
+       strlen( hc->hostname ) + 2 * VHOST_DIRLEVELS );
+    if ( strncmp( hc->hostname, "www.", 4 ) == 0 )
+       cp1 = &hc->hostname[4];
+    else
+       cp1 = hc->hostname;
+    for ( cp2 = hc->hostdir, i = 0; i < VHOST_DIRLEVELS; ++i )
+       {
+       /* Skip dots in the hostname.  If we don't, then we get vhost
+       ** directories in higher level of filestructure if dot gets
+       ** involved into path construction.  It's `while' used here instead
+       ** of `if' for it's possible to have a hostname formed with two
+       ** dots at the end of it.
+       */
+       while ( *cp1 == '.' )
+           ++cp1;
+       /* Copy a character from the hostname, or '_' if we ran out. */
+       if ( *cp1 != '\0' )
+           *cp2++ = *cp1++;
+       else
+           *cp2++ = '_';
+       /* Copy a slash. */
+       *cp2++ = '/';
+       }
+    (void) strcpy( cp2, hc->hostname );
+#else /* VHOST_DIRLEVELS */
+    httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, strlen( hc->hostname ) );
+    (void) strcpy( hc->hostdir, hc->hostname );
+#endif /* VHOST_DIRLEVELS */
+
+    /* Prepend hostdir to the filename. */
+    len = strlen( hc->expnfilename );
+    httpd_realloc_str( &tempfilename, &maxtempfilename, len );
+    (void) strcpy( tempfilename, hc->expnfilename );
+    httpd_realloc_str(
+       &hc->expnfilename, &hc->maxexpnfilename,
+       strlen( hc->hostdir ) + 1 + len );
+    (void) strcpy( hc->expnfilename, hc->hostdir );
+    (void) strcat( hc->expnfilename, "/" );
+    (void) strcat( hc->expnfilename, tempfilename );
+    return 1;
+    }
+
+
+/* Expands all symlinks in the given filename, eliding ..'s and leading /'s.
+** Returns the expanded path (pointer to static string), or (char*) 0 on
+** errors.  Also returns, in the string pointed to by restP, any trailing
+** parts of the path that don't exist.
+**
+** This is a fairly nice little routine.  It handles any size filenames
+** without excessive mallocs.
+*/
+static char*
+expand_symlinks( char* path, char** restP, int no_symlink_check, int tildemapped )
+    {
+    static char* checked;
+    static char* rest;
+    char lnk[5000];
+    static size_t maxchecked = 0, maxrest = 0;
+    size_t checkedlen, restlen, linklen, prevcheckedlen, prevrestlen;
+    int nlinks, i;
+    char* r;
+    char* cp1;
+    char* cp2;
+
+    if ( no_symlink_check )
+       {
+       /* If we are chrooted, we can actually skip the symlink-expansion,
+       ** since it's impossible to get out of the tree.  However, we still
+       ** need to do the pathinfo check, and the existing symlink expansion
+       ** code is a pretty reasonable way to do this.  So, what we do is
+       ** a single stat() of the whole filename - if it exists, then we
+       ** return it as is with nothing in restP.  If it doesn't exist, we
+       ** fall through to the existing code.
+       **
+       ** One side-effect of this is that users can't symlink to central
+       ** approved CGIs any more.  The workaround is to use the central
+       ** URL for the CGI instead of a local symlinked one.
+       */
+       struct stat sb;
+       if ( stat( path, &sb ) != -1 )
+           {
+           checkedlen = strlen( path );
+           httpd_realloc_str( &checked, &maxchecked, checkedlen );
+           (void) strcpy( checked, path );
+           /* Trim trailing slashes. */
+           while ( checked[checkedlen - 1] == '/' )
+               {
+               checked[checkedlen - 1] = '\0';
+               --checkedlen;
+               }
+           httpd_realloc_str( &rest, &maxrest, 0 );
+           rest[0] = '\0';
+           *restP = rest;
+           return checked;
+           }
+       }
+
+    /* Start out with nothing in checked and the whole filename in rest. */
+    httpd_realloc_str( &checked, &maxchecked, 1 );
+    checked[0] = '\0';
+    checkedlen = 0;
+    restlen = strlen( path );
+    httpd_realloc_str( &rest, &maxrest, restlen );
+    (void) strcpy( rest, path );
+    if ( rest[restlen - 1] == '/' )
+       rest[--restlen] = '\0';         /* trim trailing slash */
+    if ( ! tildemapped )
+       /* Remove any leading slashes. */
+       while ( rest[0] == '/' )
+           {
+           (void) ol_strcpy( rest, &(rest[1]) );
+           --restlen;
+           }
+    r = rest;
+    nlinks = 0;
+
+    /* While there are still components to check... */
+    while ( restlen > 0 )
+       {
+       /* Save current checkedlen in case we get a symlink.  Save current
+       ** restlen in case we get a non-existant component.
+       */
+       prevcheckedlen = checkedlen;
+       prevrestlen = restlen;
+
+       /* Grab one component from r and transfer it to checked. */
+       cp1 = strchr( r, '/' );
+       if ( cp1 != (char*) 0 )
+           {
+           i = cp1 - r;
+           if ( i == 0 )
+               {
+               /* Special case for absolute paths. */
+               httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 );
+               (void) strncpy( &checked[checkedlen], r, 1 );
+               checkedlen += 1;
+               }
+           else if ( strncmp( r, "..", MAX( i, 2 ) ) == 0 )
+               {
+               /* Ignore ..'s that go above the start of the path. */
+               if ( checkedlen != 0 )
+                   {
+                   cp2 = strrchr( checked, '/' );
+                   if ( cp2 == (char*) 0 )
+                       checkedlen = 0;
+                   else if ( cp2 == checked )
+                       checkedlen = 1;
+                   else
+                       checkedlen = cp2 - checked;
+                   }
+               }
+           else
+               {
+               httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 + i );
+               if ( checkedlen > 0 && checked[checkedlen-1] != '/' )
+                   checked[checkedlen++] = '/';
+               (void) strncpy( &checked[checkedlen], r, i );
+               checkedlen += i;
+               }
+           checked[checkedlen] = '\0';
+           r += i + 1;
+           restlen -= i + 1;
+           }
+       else
+           {
+           /* No slashes remaining, r is all one component. */
+           if ( strcmp( r, ".." ) == 0 )
+               {
+               /* Ignore ..'s that go above the start of the path. */
+               if ( checkedlen != 0 )
+                   {
+                   cp2 = strrchr( checked, '/' );
+                   if ( cp2 == (char*) 0 )
+                       checkedlen = 0;
+                   else if ( cp2 == checked )
+                       checkedlen = 1;
+                   else
+                       checkedlen = cp2 - checked;
+                   checked[checkedlen] = '\0';
+                   }
+               }
+           else
+               {
+               httpd_realloc_str(
+                   &checked, &maxchecked, checkedlen + 1 + restlen );
+               if ( checkedlen > 0 && checked[checkedlen-1] != '/' )
+                   checked[checkedlen++] = '/';
+               (void) strcpy( &checked[checkedlen], r );
+               checkedlen += restlen;
+               }
+           r += restlen;
+           restlen = 0;
+           }
+
+       /* Try reading the current filename as a symlink */
+       if ( checked[0] == '\0' )
+           continue;
+       linklen = readlink( checked, lnk, sizeof(lnk) - 1 );
+       if ( linklen == -1 )
+           {
+           if ( errno == EINVAL )
+               continue;               /* not a symlink */
+           if ( errno == EACCES || errno == ENOENT || errno == ENOTDIR )
+               {
+               /* That last component was bogus.  Restore and return. */
+               *restP = r - ( prevrestlen - restlen );
+               if ( prevcheckedlen == 0 )
+                   (void) strcpy( checked, "." );
+               else
+                   checked[prevcheckedlen] = '\0';
+               return checked;
+               }
+           syslog( LOG_ERR, "readlink %.80s - %m", checked );
+           return (char*) 0;
+           }
+       ++nlinks;
+       if ( nlinks > MAX_LINKS )
+           {
+           syslog( LOG_ERR, "too many symlinks in %.80s", path );
+           return (char*) 0;
+           }
+       lnk[linklen] = '\0';
+       if ( lnk[linklen - 1] == '/' )
+           lnk[--linklen] = '\0';     /* trim trailing slash */
+
+       /* Insert the link contents in front of the rest of the filename. */
+       if ( restlen != 0 )
+           {
+           (void) ol_strcpy( rest, r );
+           httpd_realloc_str( &rest, &maxrest, restlen + linklen + 1 );
+           for ( i = restlen; i >= 0; --i )
+               rest[i + linklen + 1] = rest[i];
+           (void) strcpy( rest, lnk );
+           rest[linklen] = '/';
+           restlen += linklen + 1;
+           r = rest;
+           }
+       else
+           {
+           /* There's nothing left in the filename, so the link contents
+           ** becomes the rest.
+           */
+           httpd_realloc_str( &rest, &maxrest, linklen );
+           (void) strcpy( rest, lnk );
+           restlen = linklen;
+           r = rest;
+           }
+
+       if ( rest[0] == '/' )
+           {
+           /* There must have been an absolute symlink - zero out checked. */
+           checked[0] = '\0';
+           checkedlen = 0;
+           }
+       else
+           {
+           /* Re-check this component. */
+           checkedlen = prevcheckedlen;
+           checked[checkedlen] = '\0';
+           }
+       }
+
+    /* Ok. */
+    *restP = r;
+    if ( checked[0] == '\0' )
+       (void) strcpy( checked, "." );
+    return checked;
+    }
+
+
+int
+httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc )
+    {
+    httpd_sockaddr sa;
+    socklen_t sz;
+
+    if ( ! hc->initialized )
+       {
+       hc->read_size = 0;
+       httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
+       hc->maxdecodedurl =
+           hc->maxorigfilename = hc->maxexpnfilename = hc->maxencodings =
+           hc->maxpathinfo = hc->maxquery = hc->maxaccept =
+           hc->maxaccepte = hc->maxreqhost = hc->maxhostdir =
+           hc->maxremoteuser = hc->maxresponse = 0;
+#ifdef TILDE_MAP_2
+       hc->maxaltdir = 0;
+#endif /* TILDE_MAP_2 */
+       httpd_realloc_str( &hc->decodedurl, &hc->maxdecodedurl, 1 );
+       httpd_realloc_str( &hc->origfilename, &hc->maxorigfilename, 1 );
+       httpd_realloc_str( &hc->expnfilename, &hc->maxexpnfilename, 0 );
+       httpd_realloc_str( &hc->encodings, &hc->maxencodings, 0 );
+       httpd_realloc_str( &hc->pathinfo, &hc->maxpathinfo, 0 );
+       httpd_realloc_str( &hc->query, &hc->maxquery, 0 );
+       httpd_realloc_str( &hc->accept, &hc->maxaccept, 0 );
+       httpd_realloc_str( &hc->accepte, &hc->maxaccepte, 0 );
+       httpd_realloc_str( &hc->reqhost, &hc->maxreqhost, 0 );
+       httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, 0 );
+       httpd_realloc_str( &hc->remoteuser, &hc->maxremoteuser, 0 );
+       httpd_realloc_str( &hc->response, &hc->maxresponse, 0 );
+#ifdef TILDE_MAP_2
+       httpd_realloc_str( &hc->altdir, &hc->maxaltdir, 0 );
+#endif /* TILDE_MAP_2 */
+       hc->initialized = 1;
+       }
+
+    /* Accept the new connection. */
+    sz = sizeof(sa);
+    hc->conn_fd = accept( listen_fd, &sa.sa, &sz );
+    if ( hc->conn_fd < 0 )
+       {
+       if ( errno == EWOULDBLOCK )
+           return GC_NO_MORE;
+       /* ECONNABORTED means the connection was closed by the client while
+       ** it was waiting in the listen queue.  It's not worth logging.
+       */
+       if ( errno != ECONNABORTED )
+           syslog( LOG_ERR, "accept - %m" );
+       return GC_FAIL;
+       }
+    if ( ! sockaddr_check( &sa ) )
+       {
+       syslog( LOG_ERR, "unknown sockaddr family" );
+       close( hc->conn_fd );
+       hc->conn_fd = -1;
+       return GC_FAIL;
+       }
+    (void) fcntl( hc->conn_fd, F_SETFD, 1 );
+    hc->hs = hs;
+    (void) memset( &hc->client_addr, 0, sizeof(hc->client_addr) );
+    (void) memmove( &hc->client_addr, &sa, sockaddr_len( &sa ) );
+    hc->read_idx = 0;
+    hc->checked_idx = 0;
+    hc->checked_state = CHST_FIRSTWORD;
+    hc->method = METHOD_UNKNOWN;
+    hc->status = 0;
+    hc->bytes_to_send = 0;
+    hc->bytes_sent = 0;
+    hc->encodedurl = "";
+    hc->decodedurl[0] = '\0';
+    hc->protocol = "UNKNOWN";
+    hc->origfilename[0] = '\0';
+    hc->expnfilename[0] = '\0';
+    hc->encodings[0] = '\0';
+    hc->pathinfo[0] = '\0';
+    hc->query[0] = '\0';
+    hc->referrer = "";
+    hc->useragent = "";
+    hc->accept[0] = '\0';
+    hc->accepte[0] = '\0';
+    hc->acceptl = "";
+    hc->cookie = "";
+    hc->contenttype = "";
+    hc->reqhost[0] = '\0';
+    hc->hdrhost = "";
+    hc->hostdir[0] = '\0';
+    hc->authorization = "";
+    hc->remoteuser[0] = '\0';
+    hc->response[0] = '\0';
+#ifdef TILDE_MAP_2
+    hc->altdir[0] = '\0';
+#endif /* TILDE_MAP_2 */
+    hc->responselen = 0;
+    hc->if_modified_since = (time_t) -1;
+    hc->range_if = (time_t) -1;
+    hc->contentlength = -1;
+    hc->type = "";
+    hc->hostname = (char*) 0;
+    hc->mime_flag = 1;
+    hc->one_one = 0;
+    hc->got_range = 0;
+    hc->tildemapped = 0;
+    hc->first_byte_index = 0;
+    hc->last_byte_index = -1;
+    hc->keep_alive = 0;
+    hc->should_linger = 0;
+    hc->file_address = (char*) 0;
+    return GC_OK;
+    }
+
+
+/* Checks hc->read_buf to see whether a complete request has been read so far;
+** either the first line has two words (an HTTP/0.9 request), or the first
+** line has three words and there's a blank line present.
+**
+** hc->read_idx is how much has been read in; hc->checked_idx is how much we
+** have checked so far; and hc->checked_state is the current state of the
+** finite state machine.
+*/
+int
+httpd_got_request( httpd_conn* hc )
+    {
+    char c;
+
+    for ( ; hc->checked_idx < hc->read_idx; ++hc->checked_idx )
+       {
+       c = hc->read_buf[hc->checked_idx];
+       switch ( hc->checked_state )
+           {
+           case CHST_FIRSTWORD:
+           switch ( c )
+               {
+               case ' ': case '\t':
+               hc->checked_state = CHST_FIRSTWS;
+               break;
+               case '\012': case '\015':
+               hc->checked_state = CHST_BOGUS;
+               return GR_BAD_REQUEST;
+               }
+           break;
+           case CHST_FIRSTWS:
+           switch ( c )
+               {
+               case ' ': case '\t':
+               break;
+               case '\012': case '\015':
+               hc->checked_state = CHST_BOGUS;
+               return GR_BAD_REQUEST;
+               default:
+               hc->checked_state = CHST_SECONDWORD;
+               break;
+               }
+           break;
+           case CHST_SECONDWORD:
+           switch ( c )
+               {
+               case ' ': case '\t':
+               hc->checked_state = CHST_SECONDWS;
+               break;
+               case '\012': case '\015':
+               /* The first line has only two words - an HTTP/0.9 request. */
+               return GR_GOT_REQUEST;
+               }
+           break;
+           case CHST_SECONDWS:
+           switch ( c )
+               {
+               case ' ': case '\t':
+               break;
+               case '\012': case '\015':
+               hc->checked_state = CHST_BOGUS;
+               return GR_BAD_REQUEST;
+               default:
+               hc->checked_state = CHST_THIRDWORD;
+               break;
+               }
+           break;
+           case CHST_THIRDWORD:
+           switch ( c )
+               {
+               case ' ': case '\t':
+               hc->checked_state = CHST_THIRDWS;
+               break;
+               case '\012':
+               hc->checked_state = CHST_LF;
+               break;
+               case '\015':
+               hc->checked_state = CHST_CR;
+               break;
+               }
+           break;
+           case CHST_THIRDWS:
+           switch ( c )
+               {
+               case ' ': case '\t':
+               break;
+               case '\012':
+               hc->checked_state = CHST_LF;
+               break;
+               case '\015':
+               hc->checked_state = CHST_CR;
+               break;
+               default:
+               hc->checked_state = CHST_BOGUS;
+               return GR_BAD_REQUEST;
+               }
+           break;
+           case CHST_LINE:
+           switch ( c )
+               {
+               case '\012':
+               hc->checked_state = CHST_LF;
+               break;
+               case '\015':
+               hc->checked_state = CHST_CR;
+               break;
+               }
+           break;
+           case CHST_LF:
+           switch ( c )
+               {
+               case '\012':
+               /* Two newlines in a row - a blank line - end of request. */
+               return GR_GOT_REQUEST;
+               case '\015':
+               hc->checked_state = CHST_CR;
+               break;
+               default:
+               hc->checked_state = CHST_LINE;
+               break;
+               }
+           break;
+           case CHST_CR:
+           switch ( c )
+               {
+               case '\012':
+               hc->checked_state = CHST_CRLF;
+               break;
+               case '\015':
+               /* Two returns in a row - end of request. */
+               return GR_GOT_REQUEST;
+               default:
+               hc->checked_state = CHST_LINE;
+               break;
+               }
+           break;
+           case CHST_CRLF:
+           switch ( c )
+               {
+               case '\012':
+               /* Two newlines in a row - end of request. */
+               return GR_GOT_REQUEST;
+               case '\015':
+               hc->checked_state = CHST_CRLFCR;
+               break;
+               default:
+               hc->checked_state = CHST_LINE;
+               break;
+               }
+           break;
+           case CHST_CRLFCR:
+           switch ( c )
+               {
+               case '\012': case '\015':
+               /* Two CRLFs or two CRs in a row - end of request. */
+               return GR_GOT_REQUEST;
+               default:
+               hc->checked_state = CHST_LINE;
+               break;
+               }
+           break;
+           case CHST_BOGUS:
+           return GR_BAD_REQUEST;
+           }
+       }
+    return GR_NO_REQUEST;
+    }
+
+
+int
+httpd_parse_request( httpd_conn* hc )
+    {
+    char* buf;
+    char* method_str;
+    char* url;
+    char* protocol;
+    char* reqhost;
+    char* eol;
+    char* cp;
+    char* pi;
+
+    hc->checked_idx = 0;       /* reset */
+    method_str = bufgets( hc );
+    url = strpbrk( method_str, " \t\012\015" );
+    if ( url == (char*) 0 )
+       {
+       httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+       return -1;
+       }
+    *url++ = '\0';
+    url += strspn( url, " \t\012\015" );
+    protocol = strpbrk( url, " \t\012\015" );
+    if ( protocol == (char*) 0 )
+       {
+       protocol = "HTTP/0.9";
+       hc->mime_flag = 0;
+       }
+    else
+       {
+       *protocol++ = '\0';
+       protocol += strspn( protocol, " \t\012\015" );
+       if ( *protocol != '\0' )
+           {
+           eol = strpbrk( protocol, " \t\012\015" );
+           if ( eol != (char*) 0 )
+               *eol = '\0';
+           if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 )
+               hc->one_one = 1;
+           }
+       }
+    hc->protocol = protocol;
+
+    /* Check for HTTP/1.1 absolute URL. */
+    if ( strncasecmp( url, "http://", 7 ) == 0 )
+       {
+       if ( ! hc->one_one )
+           {
+           httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+           return -1;
+           }
+       reqhost = url + 7;
+       url = strchr( reqhost, '/' );
+       if ( url == (char*) 0 )
+           {
+           httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+           return -1;
+           }
+       *url = '\0';
+       if ( strchr( reqhost, '/' ) != (char*) 0 || reqhost[0] == '.' )
+           {
+           httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+           return -1;
+           }
+       httpd_realloc_str( &hc->reqhost, &hc->maxreqhost, strlen( reqhost ) );
+       (void) strcpy( hc->reqhost, reqhost );
+       *url = '/';
+       }
+
+    if ( *url != '/' )
+       {
+       httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+       return -1;
+       }
+
+    if ( strcasecmp( method_str, httpd_method_str( METHOD_GET ) ) == 0 )
+       hc->method = METHOD_GET;
+    else if ( strcasecmp( method_str, httpd_method_str( METHOD_HEAD ) ) == 0 )
+       hc->method = METHOD_HEAD;
+    else if ( strcasecmp( method_str, httpd_method_str( METHOD_POST ) ) == 0 )
+       hc->method = METHOD_POST;
+    else if ( strcasecmp( method_str, httpd_method_str( METHOD_PUT ) ) == 0 )
+       hc->method = METHOD_PUT;
+    else if ( strcasecmp( method_str, httpd_method_str( METHOD_DELETE ) ) == 0 )
+       hc->method = METHOD_DELETE;
+    else if ( strcasecmp( method_str, httpd_method_str( METHOD_TRACE ) ) == 0 )
+       hc->method = METHOD_TRACE;
+    else
+       {
+       httpd_send_err( hc, 501, err501title, "", err501form, method_str );
+       return -1;
+       }
+
+    hc->encodedurl = url;
+    httpd_realloc_str(
+       &hc->decodedurl, &hc->maxdecodedurl, strlen( hc->encodedurl ) );
+    strdecode( hc->decodedurl, hc->encodedurl );
+
+    httpd_realloc_str(
+       &hc->origfilename, &hc->maxorigfilename, strlen( hc->decodedurl ) );
+    (void) strcpy( hc->origfilename, &hc->decodedurl[1] );
+    /* Special case for top-level URL. */
+    if ( hc->origfilename[0] == '\0' )
+       (void) strcpy( hc->origfilename, "." );
+
+    /* Extract query string from encoded URL. */
+    cp = strchr( hc->encodedurl, '?' );
+    if ( cp != (char*) 0 )
+       {
+       ++cp;
+       httpd_realloc_str( &hc->query, &hc->maxquery, strlen( cp ) );
+       (void) strcpy( hc->query, cp );
+       /* Remove query from (decoded) origfilename. */
+       cp = strchr( hc->origfilename, '?' );
+       if ( cp != (char*) 0 )
+           *cp = '\0';
+       }
+
+    de_dotdot( hc->origfilename );
+    if ( hc->origfilename[0] == '/' ||
+        ( hc->origfilename[0] == '.' && hc->origfilename[1] == '.' &&
+          ( hc->origfilename[2] == '\0' || hc->origfilename[2] == '/' ) ) )
+       {
+       httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+       return -1;
+       }
+
+    if ( hc->mime_flag )
+       {
+       /* Read the MIME headers. */
+       while ( ( buf = bufgets( hc ) ) != (char*) 0 )
+           {
+           if ( buf[0] == '\0' )
+               break;
+           if ( strncasecmp( buf, "Referer:", 8 ) == 0 )
+               {
+               cp = &buf[8];
+               cp += strspn( cp, " \t" );
+               hc->referrer = cp;
+               }
+           else if ( strncasecmp( buf, "Referrer:", 9 ) == 0 )
+               {
+               cp = &buf[9];
+               cp += strspn( cp, " \t" );
+               hc->referrer = cp;
+               }
+           else if ( strncasecmp( buf, "User-Agent:", 11 ) == 0 )
+               {
+               cp = &buf[11];
+               cp += strspn( cp, " \t" );
+               hc->useragent = cp;
+               }
+           else if ( strncasecmp( buf, "Host:", 5 ) == 0 )
+               {
+               cp = &buf[5];
+               cp += strspn( cp, " \t" );
+               hc->hdrhost = cp;
+               cp = strchr( hc->hdrhost, ':' );
+               if ( cp != (char*) 0 )
+                   *cp = '\0';
+               if ( strchr( hc->hdrhost, '/' ) != (char*) 0 || hc->hdrhost[0] == '.' )
+                   {
+                   httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+                   return -1;
+                   }
+               }
+           else if ( strncasecmp( buf, "Accept:", 7 ) == 0 )
+               {
+               cp = &buf[7];
+               cp += strspn( cp, " \t" );
+               if ( hc->accept[0] != '\0' )
+                   {
+                   if ( strlen( hc->accept ) > 5000 )
+                       {
+                       syslog(
+                           LOG_ERR, "%.80s way too much Accept: data",
+                           httpd_ntoa( &hc->client_addr ) );
+                       continue;
+                       }
+                   httpd_realloc_str(
+                       &hc->accept, &hc->maxaccept,
+                       strlen( hc->accept ) + 2 + strlen( cp ) );
+                   (void) strcat( hc->accept, ", " );
+                   }
+               else
+                   httpd_realloc_str(
+                       &hc->accept, &hc->maxaccept, strlen( cp ) );
+               (void) strcat( hc->accept, cp );
+               }
+           else if ( strncasecmp( buf, "Accept-Encoding:", 16 ) == 0 )
+               {
+               cp = &buf[16];
+               cp += strspn( cp, " \t" );
+               if ( hc->accepte[0] != '\0' )
+                   {
+                   if ( strlen( hc->accepte ) > 5000 )
+                       {
+                       syslog(
+                           LOG_ERR, "%.80s way too much Accept-Encoding: data",
+                           httpd_ntoa( &hc->client_addr ) );
+                       continue;
+                       }
+                   httpd_realloc_str(
+                       &hc->accepte, &hc->maxaccepte,
+                       strlen( hc->accepte ) + 2 + strlen( cp ) );
+                   (void) strcat( hc->accepte, ", " );
+                   }
+               else
+                   httpd_realloc_str(
+                       &hc->accepte, &hc->maxaccepte, strlen( cp ) );
+               (void) strcpy( hc->accepte, cp );
+               }
+           else if ( strncasecmp( buf, "Accept-Language:", 16 ) == 0 )
+               {
+               cp = &buf[16];
+               cp += strspn( cp, " \t" );
+               hc->acceptl = cp;
+               }
+           else if ( strncasecmp( buf, "If-Modified-Since:", 18 ) == 0 )
+               {
+               cp = &buf[18];
+               hc->if_modified_since = tdate_parse( cp );
+               if ( hc->if_modified_since == (time_t) -1 )
+                   syslog( LOG_DEBUG, "unparsable time: %.80s", cp );
+               }
+           else if ( strncasecmp( buf, "Cookie:", 7 ) == 0 )
+               {
+               cp = &buf[7];
+               cp += strspn( cp, " \t" );
+               hc->cookie = cp;
+               }
+           else if ( strncasecmp( buf, "Range:", 6 ) == 0 )
+               {
+               /* Only support %d- and %d-%d, not %d-%d,%d-%d or -%d. */
+               if ( strchr( buf, ',' ) == (char*) 0 )
+                   {
+                   char* cp_dash;
+                   cp = strpbrk( buf, "=" );
+                   if ( cp != (char*) 0 )
+                       {
+                       cp_dash = strchr( cp + 1, '-' );
+                       if ( cp_dash != (char*) 0 && cp_dash != cp + 1 )
+                           {
+                           *cp_dash = '\0';
+                           hc->got_range = 1;
+                           hc->first_byte_index = atoll( cp + 1 );
+                           if ( hc->first_byte_index < 0 )
+                               hc->first_byte_index = 0;
+                           if ( isdigit( (int) cp_dash[1] ) )
+                               {
+                               hc->last_byte_index = atoll( cp_dash + 1 );
+                               if ( hc->last_byte_index < 0 )
+                                   hc->last_byte_index = -1;
+                               }
+                           }
+                       }
+                   }
+               }
+           else if ( strncasecmp( buf, "Range-If:", 9 ) == 0 ||
+                     strncasecmp( buf, "If-Range:", 9 ) == 0 )
+               {
+               cp = &buf[9];
+               hc->range_if = tdate_parse( cp );
+               if ( hc->range_if == (time_t) -1 )
+                   syslog( LOG_DEBUG, "unparsable time: %.80s", cp );
+               }
+           else if ( strncasecmp( buf, "Content-Type:", 13 ) == 0 )
+               {
+               cp = &buf[13];
+               cp += strspn( cp, " \t" );
+               hc->contenttype = cp;
+               }
+           else if ( strncasecmp( buf, "Content-Length:", 15 ) == 0 )
+               {
+               cp = &buf[15];
+               hc->contentlength = atol( cp );
+               }
+           else if ( strncasecmp( buf, "Authorization:", 14 ) == 0 )
+               {
+               cp = &buf[14];
+               cp += strspn( cp, " \t" );
+               hc->authorization = cp;
+               }
+           else if ( strncasecmp( buf, "Connection:", 11 ) == 0 )
+               {
+               cp = &buf[11];
+               cp += strspn( cp, " \t" );
+               if ( strcasecmp( cp, "keep-alive" ) == 0 )
+                   hc->keep_alive = 1;
+               }
+#ifdef LOG_UNKNOWN_HEADERS
+           else if ( strncasecmp( buf, "Accept-Charset:", 15 ) == 0 ||
+                     strncasecmp( buf, "Accept-Language:", 16 ) == 0 ||
+                     strncasecmp( buf, "Agent:", 6 ) == 0 ||
+                     strncasecmp( buf, "Cache-Control:", 14 ) == 0 ||
+                     strncasecmp( buf, "Cache-Info:", 11 ) == 0 ||
+                     strncasecmp( buf, "Charge-To:", 10 ) == 0 ||
+                     strncasecmp( buf, "Client-IP:", 10 ) == 0 ||
+                     strncasecmp( buf, "Date:", 5 ) == 0 ||
+                     strncasecmp( buf, "Extension:", 10 ) == 0 ||
+                     strncasecmp( buf, "Forwarded:", 10 ) == 0 ||
+                     strncasecmp( buf, "From:", 5 ) == 0 ||
+                     strncasecmp( buf, "HTTP-Version:", 13 ) == 0 ||
+                     strncasecmp( buf, "Max-Forwards:", 13 ) == 0 ||
+                     strncasecmp( buf, "Message-Id:", 11 ) == 0 ||
+                     strncasecmp( buf, "MIME-Version:", 13 ) == 0 ||
+                     strncasecmp( buf, "Negotiate:", 10 ) == 0 ||
+                     strncasecmp( buf, "Pragma:", 7 ) == 0 ||
+                     strncasecmp( buf, "Proxy-Agent:", 12 ) == 0 ||
+                     strncasecmp( buf, "Proxy-Connection:", 17 ) == 0 ||
+                     strncasecmp( buf, "Security-Scheme:", 16 ) == 0 ||
+                     strncasecmp( buf, "Session-Id:", 11 ) == 0 ||
+                     strncasecmp( buf, "UA-Color:", 9 ) == 0 ||
+                     strncasecmp( buf, "UA-CPU:", 7 ) == 0 ||
+                     strncasecmp( buf, "UA-Disp:", 8 ) == 0 ||
+                     strncasecmp( buf, "UA-OS:", 6 ) == 0 ||
+                     strncasecmp( buf, "UA-Pixels:", 10 ) == 0 ||
+                     strncasecmp( buf, "User:", 5 ) == 0 ||
+                     strncasecmp( buf, "Via:", 4 ) == 0 ||
+                     strncasecmp( buf, "X-", 2 ) == 0 )
+               ; /* ignore */
+           else
+               syslog( LOG_DEBUG, "unknown request header: %.80s", buf );
+#endif /* LOG_UNKNOWN_HEADERS */
+           }
+       }
+
+    if ( hc->one_one )
+       {
+       /* Check that HTTP/1.1 requests specify a host, as required. */
+       if ( hc->reqhost[0] == '\0' && hc->hdrhost[0] == '\0' )
+           {
+           httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+           return -1;
+           }
+
+       /* If the client wants to do keep-alives, it might also be doing
+       ** pipelining.  There's no way for us to tell.  Since we don't
+       ** implement keep-alives yet, if we close such a connection there
+       ** might be unread pipelined requests waiting.  So, we have to
+       ** do a lingering close.
+       */
+       if ( hc->keep_alive )
+           hc->should_linger = 1;
+       }
+
+    /* Ok, the request has been parsed.  Now we resolve stuff that
+    ** may require the entire request.
+    */
+
+    /* Copy original filename to expanded filename. */
+    httpd_realloc_str(
+       &hc->expnfilename, &hc->maxexpnfilename, strlen( hc->origfilename ) );
+    (void) strcpy( hc->expnfilename, hc->origfilename );
+
+    /* Tilde mapping. */
+    if ( hc->expnfilename[0] == '~' )
+       {
+#ifdef TILDE_MAP_1
+       if ( ! tilde_map_1( hc ) )
+           {
+           httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
+           return -1;
+           }
+#endif /* TILDE_MAP_1 */
+#ifdef TILDE_MAP_2
+       if ( ! tilde_map_2( hc ) )
+           {
+           httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
+           return -1;
+           }
+#endif /* TILDE_MAP_2 */
+       }
+
+    /* Virtual host mapping. */
+    if ( hc->hs->vhost )
+       if ( ! vhost_map( hc ) )
+           {
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           return -1;
+           }
+
+    /* Expand all symbolic links in the filename.  This also gives us
+    ** any trailing non-existing components, for pathinfo.
+    */
+    cp = expand_symlinks( hc->expnfilename, &pi, hc->hs->no_symlink_check, hc->tildemapped );
+    if ( cp == (char*) 0 )
+       {
+       httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+       return -1;
+       }
+    httpd_realloc_str( &hc->expnfilename, &hc->maxexpnfilename, strlen( cp ) );
+    (void) strcpy( hc->expnfilename, cp );
+    httpd_realloc_str( &hc->pathinfo, &hc->maxpathinfo, strlen( pi ) );
+    (void) strcpy( hc->pathinfo, pi );
+
+    /* Remove pathinfo stuff from the original filename too. */
+    if ( hc->pathinfo[0] != '\0' )
+       {
+       int i;
+       i = strlen( hc->origfilename ) - strlen( hc->pathinfo );
+       if ( i > 0 && strcmp( &hc->origfilename[i], hc->pathinfo ) == 0 )
+           hc->origfilename[i - 1] = '\0';
+       }
+
+    /* If the expanded filename is an absolute path, check that it's still
+    ** within the current directory or the alternate directory.
+    */
+    if ( hc->expnfilename[0] == '/' )
+       {
+       if ( strncmp(
+                hc->expnfilename, hc->hs->cwd, strlen( hc->hs->cwd ) ) == 0 )
+           {
+           /* Elide the current directory. */
+           (void) ol_strcpy(
+               hc->expnfilename, &hc->expnfilename[strlen( hc->hs->cwd )] );
+           }
+#ifdef TILDE_MAP_2
+       else if ( hc->altdir[0] != '\0' &&
+                 ( strncmp(
+                      hc->expnfilename, hc->altdir,
+                      strlen( hc->altdir ) ) == 0 &&
+                   ( hc->expnfilename[strlen( hc->altdir )] == '\0' ||
+                     hc->expnfilename[strlen( hc->altdir )] == '/' ) ) )
+           {}
+#endif /* TILDE_MAP_2 */
+       else
+           {
+           syslog(
+               LOG_NOTICE, "%.80s URL \"%.80s\" goes outside the web tree",
+               httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+           httpd_send_err(
+               hc, 403, err403title, "",
+               ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file outside the permitted web server directory tree.\n" ),
+               hc->encodedurl );
+           return -1;
+           }
+       }
+
+    return 0;
+    }
+
+
+static char*
+bufgets( httpd_conn* hc )
+    {
+    int i;
+    char c;
+
+    for ( i = hc->checked_idx; hc->checked_idx < hc->read_idx; ++hc->checked_idx )
+       {
+       c = hc->read_buf[hc->checked_idx];
+       if ( c == '\012' || c == '\015' )
+           {
+           hc->read_buf[hc->checked_idx] = '\0';
+           ++hc->checked_idx;
+           if ( c == '\015' && hc->checked_idx < hc->read_idx &&
+                hc->read_buf[hc->checked_idx] == '\012' )
+               {
+               hc->read_buf[hc->checked_idx] = '\0';
+               ++hc->checked_idx;
+               }
+           return &(hc->read_buf[i]);
+           }
+       }
+    return (char*) 0;
+    }
+
+
+static void
+de_dotdot( char* file )
+    {
+    char* cp;
+    char* cp2;
+    int l;
+
+    /* Collapse any multiple / sequences. */
+    while ( ( cp = strstr( file, "//") ) != (char*) 0 )
+       {
+       for ( cp2 = cp + 2; *cp2 == '/'; ++cp2 )
+           continue;
+       (void) ol_strcpy( cp + 1, cp2 );
+       }
+
+    /* Remove leading ./ and any /./ sequences. */
+    while ( strncmp( file, "./", 2 ) == 0 )
+       (void) ol_strcpy( file, file + 2 );
+    while ( ( cp = strstr( file, "/./") ) != (char*) 0 )
+       (void) ol_strcpy( cp, cp + 2 );
+
+    /* Alternate between removing leading ../ and removing xxx/../ */
+    for (;;)
+       {
+       while ( strncmp( file, "../", 3 ) == 0 )
+           (void) ol_strcpy( file, file + 3 );
+       cp = strstr( file, "/../" );
+       if ( cp == (char*) 0 )
+           break;
+       for ( cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2 )
+           continue;
+       (void) ol_strcpy( cp2 + 1, cp + 4 );
+       }
+
+    /* Also elide any xxx/.. at the end. */
+    while ( ( l = strlen( file ) ) > 3 &&
+           strcmp( ( cp = file + l - 3 ), "/.." ) == 0 )
+       {
+       for ( cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2 )
+           continue;
+       if ( cp2 < file )
+           break;
+       *cp2 = '\0';
+       }
+    }
+
+
+void
+httpd_close_conn( httpd_conn* hc, struct timeval* nowP )
+    {
+    make_log_entry( hc, nowP );
+
+    if ( hc->file_address != (char*) 0 )
+       {
+       mmc_unmap( hc->file_address, &(hc->sb), nowP );
+       hc->file_address = (char*) 0;
+       }
+    if ( hc->conn_fd >= 0 )
+       {
+       (void) close( hc->conn_fd );
+       hc->conn_fd = -1;
+       }
+    }
+
+void
+httpd_destroy_conn( httpd_conn* hc )
+    {
+    if ( hc->initialized )
+       {
+       free( (void*) hc->read_buf );
+       free( (void*) hc->decodedurl );
+       free( (void*) hc->origfilename );
+       free( (void*) hc->expnfilename );
+       free( (void*) hc->encodings );
+       free( (void*) hc->pathinfo );
+       free( (void*) hc->query );
+       free( (void*) hc->accept );
+       free( (void*) hc->accepte );
+       free( (void*) hc->reqhost );
+       free( (void*) hc->hostdir );
+       free( (void*) hc->remoteuser );
+       free( (void*) hc->response );
+#ifdef TILDE_MAP_2
+       free( (void*) hc->altdir );
+#endif /* TILDE_MAP_2 */
+       hc->initialized = 0;
+       }
+    }
+
+
+struct mime_entry {
+    char* ext;
+    size_t ext_len;
+    char* val;
+    size_t val_len;
+    };
+static struct mime_entry enc_tab[] = {
+#include "mime_encodings.h"
+    };
+static const int n_enc_tab = sizeof(enc_tab) / sizeof(*enc_tab);
+static struct mime_entry typ_tab[] = {
+#include "mime_types.h"
+    };
+static const int n_typ_tab = sizeof(typ_tab) / sizeof(*typ_tab);
+
+
+/* qsort comparison routine */
+static int
+ext_compare( const void* v1, const void* v2 )
+    {
+    const struct mime_entry* m1 = (const struct mime_entry*) v1;
+    const struct mime_entry* m2 = (const struct mime_entry*) v2;
+
+    return strcmp( m1->ext, m2->ext );
+    }
+
+
+static void
+init_mime( void )
+    {
+    int i;
+
+    /* Sort the tables so we can do binary search. */
+    qsort( enc_tab, n_enc_tab, sizeof(*enc_tab), ext_compare );
+    qsort( typ_tab, n_typ_tab, sizeof(*typ_tab), ext_compare );
+
+    /* Fill in the lengths. */
+    for ( i = 0; i < n_enc_tab; ++i )
+       {
+       enc_tab[i].ext_len = strlen( enc_tab[i].ext );
+       enc_tab[i].val_len = strlen( enc_tab[i].val );
+       }
+    for ( i = 0; i < n_typ_tab; ++i )
+       {
+       typ_tab[i].ext_len = strlen( typ_tab[i].ext );
+       typ_tab[i].val_len = strlen( typ_tab[i].val );
+       }
+
+    }
+
+
+/* Figure out MIME encodings and type based on the filename.  Multiple
+** encodings are separated by commas, and are listed in the order in
+** which they were applied to the file.
+*/
+static void
+figure_mime( httpd_conn* hc )
+    {
+    char* prev_dot;
+    char* dot;
+    char* ext;
+    int me_indexes[100], n_me_indexes;
+    size_t ext_len, encodings_len;
+    int i, top, bot, mid;
+    int r;
+    char* default_type = "text/plain; charset=%s";
+
+    /* Peel off encoding extensions until there aren't any more. */
+    n_me_indexes = 0;
+    for ( prev_dot = &hc->expnfilename[strlen(hc->expnfilename)]; ; prev_dot = dot )
+       {
+       for ( dot = prev_dot - 1; dot >= hc->expnfilename && *dot != '.'; --dot )
+           ;
+       if ( dot < hc->expnfilename )
+           {
+           /* No dot found.  No more encoding extensions, and no type
+           ** extension either.
+           */
+           hc->type = default_type;
+           goto done;
+           }
+       ext = dot + 1;
+       ext_len = prev_dot - ext;
+       /* Search the encodings table.  Linear search is fine here, there
+       ** are only a few entries.
+       */
+       for ( i = 0; i < n_enc_tab; ++i )
+           {
+           if ( ext_len == enc_tab[i].ext_len && strncasecmp( ext, enc_tab[i].ext, ext_len ) == 0 )
+               {
+               if ( n_me_indexes < sizeof(me_indexes)/sizeof(*me_indexes) )
+                   {
+                   me_indexes[n_me_indexes] = i;
+                   ++n_me_indexes;
+                   }
+               goto next;
+               }
+           }
+       /* No encoding extension found.  Break and look for a type extension. */
+       break;
+
+       next: ;
+       }
+
+    /* Binary search for a matching type extension. */
+    top = n_typ_tab - 1;
+    bot = 0;
+    while ( top >= bot )
+       {
+       mid = ( top + bot ) / 2;
+       r = strncasecmp( ext, typ_tab[mid].ext, ext_len );
+       if ( r < 0 )
+           top = mid - 1;
+       else if ( r > 0 )
+           bot = mid + 1;
+       else
+           if ( ext_len < typ_tab[mid].ext_len )
+               top = mid - 1;
+           else if ( ext_len > typ_tab[mid].ext_len )
+               bot = mid + 1;
+           else
+               {
+               hc->type = typ_tab[mid].val;
+               goto done;
+               }
+       }
+    hc->type = default_type;
+
+    done:
+
+    /* The last thing we do is actually generate the mime-encoding header. */
+    hc->encodings[0] = '\0';
+    encodings_len = 0;
+    for ( i = n_me_indexes - 1; i >= 0; --i )
+       {
+       httpd_realloc_str(
+           &hc->encodings, &hc->maxencodings,
+           encodings_len + enc_tab[me_indexes[i]].val_len + 1 );
+       if ( hc->encodings[0] != '\0' )
+           {
+           (void) strcpy( &hc->encodings[encodings_len], "," );
+           ++encodings_len;
+           }
+       (void) strcpy( &hc->encodings[encodings_len], enc_tab[me_indexes[i]].val );
+       encodings_len += enc_tab[me_indexes[i]].val_len;
+       }
+
+    }
+
+
+#ifdef CGI_TIMELIMIT
+static void
+cgi_kill2( ClientData client_data, struct timeval* nowP )
+    {
+    pid_t pid;
+
+    pid = (pid_t) client_data.i;
+    if ( kill( pid, SIGKILL ) == 0 )
+       syslog( LOG_WARNING, "hard-killed CGI process %d", pid );
+    }
+
+static void
+cgi_kill( ClientData client_data, struct timeval* nowP )
+    {
+    pid_t pid;
+
+    pid = (pid_t) client_data.i;
+    if ( kill( pid, SIGINT ) == 0 )
+       {
+       syslog( LOG_WARNING, "killed CGI process %d", pid );
+       /* In case this isn't enough, schedule an uncatchable kill. */
+       if ( tmr_create( nowP, cgi_kill2, client_data, 5 * 1000L, 0 ) == (Timer*) 0 )
+           {
+           syslog( LOG_CRIT, "tmr_create(cgi_kill2) failed" );
+           exit( 1 );
+           }
+       }
+    }
+#endif /* CGI_TIMELIMIT */
+
+
+#ifdef GENERATE_INDEXES
+
+/* qsort comparison routine */
+static int
+name_compare( const void* v1, const void* v2 )
+    {
+    const char** c1 = (const char**) v1;
+    const char** c2 = (const char**) v2;
+    return strcmp( *c1, *c2 );
+    }
+
+
+static int
+ls( httpd_conn* hc )
+    {
+    DIR* dirp;
+    struct dirent* de;
+    int namlen;
+    static int maxnames = 0;
+    int nnames;
+    static char* names;
+    static char** nameptrs;
+    static char* name;
+    static size_t maxname = 0;
+    static char* rname;
+    static size_t maxrname = 0;
+    static char* encrname;
+    static size_t maxencrname = 0;
+    FILE* fp;
+    int i, r;
+    struct stat sb;
+    struct stat lsb;
+    char modestr[20];
+    char* linkprefix;
+    char lnk[MAXPATHLEN+1];
+    int linklen;
+    char* fileclass;
+    time_t now;
+    char* timestr;
+    ClientData client_data;
+
+    dirp = opendir( hc->expnfilename );
+    if ( dirp == (DIR*) 0 )
+       {
+       syslog( LOG_ERR, "opendir %.80s - %m", hc->expnfilename );
+       httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
+       return -1;
+       }
+
+    if ( hc->method == METHOD_HEAD )
+       {
+       closedir( dirp );
+       send_mime(
+           hc, 200, ok200title, "", "", "text/html; charset=%s", (off_t) -1,
+           hc->sb.st_mtime );
+       }
+    else if ( hc->method == METHOD_GET )
+       {
+       if ( hc->hs->cgi_limit != 0 && hc->hs->cgi_count >= hc->hs->cgi_limit )
+           {
+           closedir( dirp );
+           httpd_send_err(
+               hc, 503, httpd_err503title, "", httpd_err503form,
+               hc->encodedurl );
+           return -1;
+           }
+       ++hc->hs->cgi_count;
+       r = fork( );
+       if ( r < 0 )
+           {
+           syslog( LOG_ERR, "fork - %m" );
+           closedir( dirp );
+           httpd_send_err(
+               hc, 500, err500title, "", err500form, hc->encodedurl );
+           return -1;
+           }
+       if ( r == 0 )
+           {
+           /* Child process. */
+           sub_process = 1;
+           httpd_unlisten( hc->hs );
+           send_mime(
+               hc, 200, ok200title, "", "", "text/html; charset=%s",
+               (off_t) -1, hc->sb.st_mtime );
+           httpd_write_response( hc );
+
+#ifdef CGI_NICE
+           /* Set priority. */
+           (void) nice( CGI_NICE );
+#endif /* CGI_NICE */
+
+           /* Open a stdio stream so that we can use fprintf, which is more
+           ** efficient than a bunch of separate write()s.  We don't have
+           ** to worry about double closes or file descriptor leaks cause
+           ** we're in a subprocess.
+           */
+           fp = fdopen( hc->conn_fd, "w" );
+           if ( fp == (FILE*) 0 )
+               {
+               syslog( LOG_ERR, "fdopen - %m" );
+               httpd_send_err(
+                   hc, 500, err500title, "", err500form, hc->encodedurl );
+               httpd_write_response( hc );
+               closedir( dirp );
+               exit( 1 );
+               }
+
+           (void) fprintf( fp, "\
+<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n\
+\n\
+<html>\n\
+\n\
+  <head>\n\
+    <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\n\
+    <title>Index of %.80s</title>\n\
+  </head>\n\
+\n\
+  <body bgcolor=\"#99cc99\" text=\"#000000\" link=\"#2020ff\" vlink=\"#4040cc\">\n\
+\n\
+    <h2>Index of %.80s</h2>\n\
+\n\
+    <pre>\n\
+mode  links    bytes  last-changed  name\n\
+    <hr>",
+               hc->encodedurl, hc->encodedurl );
+
+           /* Read in names. */
+           nnames = 0;
+           while ( ( de = readdir( dirp ) ) != 0 )     /* dirent or direct */
+               {
+               if ( nnames >= maxnames )
+                   {
+                   if ( maxnames == 0 )
+                       {
+                       maxnames = 100;
+                       names = NEW( char, maxnames * ( MAXPATHLEN + 1 ) );
+                       nameptrs = NEW( char*, maxnames );
+                       }
+                   else
+                       {
+                       maxnames *= 2;
+                       names = RENEW( names, char, maxnames * ( MAXPATHLEN + 1 ) );
+                       nameptrs = RENEW( nameptrs, char*, maxnames );
+                       }
+                   if ( names == (char*) 0 || nameptrs == (char**) 0 )
+                       {
+                       syslog( LOG_ERR, "out of memory reallocating directory names" );
+                       exit( 1 );
+                       }
+                   for ( i = 0; i < maxnames; ++i )
+                       nameptrs[i] = &names[i * ( MAXPATHLEN + 1 )];
+                   }
+               namlen = NAMLEN(de);
+               (void) strncpy( nameptrs[nnames], de->d_name, namlen );
+               nameptrs[nnames][namlen] = '\0';
+               ++nnames;
+               }
+           closedir( dirp );
+
+           /* Sort the names. */
+           qsort( nameptrs, nnames, sizeof(*nameptrs), name_compare );
+
+           /* Generate output. */
+           for ( i = 0; i < nnames; ++i )
+               {
+               httpd_realloc_str(
+                   &name, &maxname,
+                   strlen( hc->expnfilename ) + 1 + strlen( nameptrs[i] ) );
+               httpd_realloc_str(
+                   &rname, &maxrname,
+                   strlen( hc->origfilename ) + 1 + strlen( nameptrs[i] ) );
+               if ( hc->expnfilename[0] == '\0' ||
+                    strcmp( hc->expnfilename, "." ) == 0 )
+                   {
+                   (void) strcpy( name, nameptrs[i] );
+                   (void) strcpy( rname, nameptrs[i] );
+                   }
+               else
+                   {
+                   (void) my_snprintf( name, maxname,
+                       "%s/%s", hc->expnfilename, nameptrs[i] );
+                   if ( strcmp( hc->origfilename, "." ) == 0 )
+                       (void) my_snprintf( rname, maxrname,
+                           "%s", nameptrs[i] );
+                   else
+                       (void) my_snprintf( rname, maxrname,
+                           "%s%s", hc->origfilename, nameptrs[i] );
+                   }
+               httpd_realloc_str(
+                   &encrname, &maxencrname, 3 * strlen( rname ) + 1 );
+               strencode( encrname, maxencrname, rname );
+
+               if ( stat( name, &sb ) < 0 || lstat( name, &lsb ) < 0 )
+                   continue;
+
+               linkprefix = "";
+               lnk[0] = '\0';
+               /* Break down mode word.  First the file type. */
+               switch ( lsb.st_mode & S_IFMT )
+                   {
+                   case S_IFIFO:  modestr[0] = 'p'; break;
+                   case S_IFCHR:  modestr[0] = 'c'; break;
+                   case S_IFDIR:  modestr[0] = 'd'; break;
+                   case S_IFBLK:  modestr[0] = 'b'; break;
+                   case S_IFREG:  modestr[0] = '-'; break;
+                   case S_IFSOCK: modestr[0] = 's'; break;
+                   case S_IFLNK:  modestr[0] = 'l';
+                   linklen = readlink( name, lnk, sizeof(lnk) - 1 );
+                   if ( linklen != -1 )
+                       {
+                       lnk[linklen] = '\0';
+                       linkprefix = " -&gt; ";
+                       }
+                   break;
+                   default:       modestr[0] = '?'; break;
+                   }
+               /* Now the world permissions.  Owner and group permissions
+               ** are not of interest to web clients.
+               */
+               modestr[1] = ( lsb.st_mode & S_IROTH ) ? 'r' : '-';
+               modestr[2] = ( lsb.st_mode & S_IWOTH ) ? 'w' : '-';
+               modestr[3] = ( lsb.st_mode & S_IXOTH ) ? 'x' : '-';
+               modestr[4] = '\0';
+
+               /* We also leave out the owner and group name, they are
+               ** also not of interest to web clients.  Plus if we're
+               ** running under chroot(), they would require a copy
+               ** of /etc/passwd and /etc/group, which we want to avoid.
+               */
+
+               /* Get time string. */
+               now = time( (time_t*) 0 );
+               timestr = ctime( &lsb.st_mtime );
+               timestr[ 0] = timestr[ 4];
+               timestr[ 1] = timestr[ 5];
+               timestr[ 2] = timestr[ 6];
+               timestr[ 3] = ' ';
+               timestr[ 4] = timestr[ 8];
+               timestr[ 5] = timestr[ 9];
+               timestr[ 6] = ' ';
+               if ( now - lsb.st_mtime > 60*60*24*182 )        /* 1/2 year */
+                   {
+                   timestr[ 7] = ' ';
+                   timestr[ 8] = timestr[20];
+                   timestr[ 9] = timestr[21];
+                   timestr[10] = timestr[22];
+                   timestr[11] = timestr[23];
+                   }
+               else
+                   {
+                   timestr[ 7] = timestr[11];
+                   timestr[ 8] = timestr[12];
+                   timestr[ 9] = ':';
+                   timestr[10] = timestr[14];
+                   timestr[11] = timestr[15];
+                   }
+               timestr[12] = '\0';
+
+               /* The ls -F file class. */
+               switch ( sb.st_mode & S_IFMT )
+                   {
+                   case S_IFDIR:  fileclass = "/"; break;
+                   case S_IFSOCK: fileclass = "="; break;
+                   case S_IFLNK:  fileclass = "@"; break;
+                   default:
+                   fileclass = ( sb.st_mode & S_IXOTH ) ? "*" : "";
+                   break;
+                   }
+
+               /* And print. */
+               (void)  fprintf( fp,
+                  "%s %3ld  %10lld  %s  <a href=\"/%.500s%s\">%.80s</a>%s%s%s\n",
+                   modestr, (long) lsb.st_nlink, (long long) lsb.st_size,
+                   timestr, encrname, S_ISDIR(sb.st_mode) ? "/" : "",
+                   nameptrs[i], linkprefix, lnk, fileclass );
+               }
+
+           (void) fprintf( fp, "    </pre>\n  </body>\n</html>\n" );
+           (void) fclose( fp );
+           exit( 0 );
+           }
+
+       /* Parent process. */
+       closedir( dirp );
+       syslog( LOG_DEBUG, "spawned indexing process %d for directory '%.200s'", r, hc->expnfilename );
+#ifdef CGI_TIMELIMIT
+       /* Schedule a kill for the child process, in case it runs too long */
+       client_data.i = r;
+       if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 )
+           {
+           syslog( LOG_CRIT, "tmr_create(cgi_kill ls) failed" );
+           exit( 1 );
+           }
+#endif /* CGI_TIMELIMIT */
+       hc->status = 200;
+       hc->bytes_sent = CGI_BYTECOUNT;
+       hc->should_linger = 0;
+       }
+    else
+       {
+       closedir( dirp );
+       httpd_send_err(
+           hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) );
+       return -1;
+       }
+
+    return 0;
+    }
+
+#endif /* GENERATE_INDEXES */
+
+
+static char*
+build_env( char* fmt, char* arg )
+    {
+    char* cp;
+    size_t size;
+    static char* buf;
+    static size_t maxbuf = 0;
+
+    size = strlen( fmt ) + strlen( arg );
+    if ( size > maxbuf )
+       httpd_realloc_str( &buf, &maxbuf, size );
+    (void) my_snprintf( buf, maxbuf, fmt, arg );
+    cp = strdup( buf );
+    if ( cp == (char*) 0 )
+       {
+       syslog( LOG_ERR, "out of memory copying environment variable" );
+       exit( 1 );
+       }
+    return cp;
+    }
+
+
+#ifdef SERVER_NAME_LIST
+static char*
+hostname_map( char* hostname )
+    {
+    int len, n;
+    static char* list[] = { SERVER_NAME_LIST };
+
+    len = strlen( hostname );
+    for ( n = sizeof(list) / sizeof(*list) - 1; n >= 0; --n )
+       if ( strncasecmp( hostname, list[n], len ) == 0 )
+           if ( list[n][len] == '/' )  /* check in case of a substring match */
+               return &list[n][len + 1];
+    return (char*) 0;
+    }
+#endif /* SERVER_NAME_LIST */
+
+
+/* Set up environment variables. Be real careful here to avoid
+** letting malicious clients overrun a buffer.  We don't have
+** to worry about freeing stuff since we're a sub-process.
+*/
+static char**
+make_envp( httpd_conn* hc )
+    {
+    static char* envp[50];
+    int envn;
+    char* cp;
+    char buf[256];
+
+    envn = 0;
+    envp[envn++] = build_env( "PATH=%s", CGI_PATH );
+#ifdef CGI_LD_LIBRARY_PATH
+    envp[envn++] = build_env( "LD_LIBRARY_PATH=%s", CGI_LD_LIBRARY_PATH );
+#endif /* CGI_LD_LIBRARY_PATH */
+    envp[envn++] = build_env( "SERVER_SOFTWARE=%s", SERVER_SOFTWARE );
+    if ( hc->hs->vhost && hc->hostname != (char*) 0 && hc->hostname[0] != '\0' )
+       cp = hc->hostname;
+    else if ( hc->hdrhost != (char*) 0 && hc->hdrhost[0] != '\0' )
+       cp = hc->hdrhost;
+    else if ( hc->reqhost != (char*) 0 && hc->reqhost[0] != '\0' )
+       cp = hc->reqhost;
+    else
+       cp = hc->hs->server_hostname;
+    if ( cp != (char*) 0 )
+       envp[envn++] = build_env( "SERVER_NAME=%s", cp );
+    envp[envn++] = "GATEWAY_INTERFACE=CGI/1.1";
+    envp[envn++] = build_env("SERVER_PROTOCOL=%s", hc->protocol);
+    (void) my_snprintf( buf, sizeof(buf), "%d", (int) hc->hs->port );
+    envp[envn++] = build_env( "SERVER_PORT=%s", buf );
+    envp[envn++] = build_env(
+       "REQUEST_METHOD=%s", httpd_method_str( hc->method ) );
+    if ( hc->pathinfo[0] != '\0' )
+       {
+       char* cp2;
+       size_t l;
+       envp[envn++] = build_env( "PATH_INFO=/%s", hc->pathinfo );
+       l = strlen( hc->hs->cwd ) + strlen( hc->pathinfo ) + 1;
+       cp2 = NEW( char, l );
+       if ( cp2 != (char*) 0 )
+           {
+           (void) my_snprintf( cp2, l, "%s%s", hc->hs->cwd, hc->pathinfo );
+           envp[envn++] = build_env( "PATH_TRANSLATED=%s", cp2 );
+           }
+       }
+    envp[envn++] = build_env(
+       "SCRIPT_NAME=/%s", strcmp( hc->origfilename, "." ) == 0 ?
+       "" : hc->origfilename );
+    if ( hc->query[0] != '\0')
+       envp[envn++] = build_env( "QUERY_STRING=%s", hc->query );
+    envp[envn++] = build_env(
+       "REMOTE_ADDR=%s", httpd_ntoa( &hc->client_addr ) );
+    if ( hc->referrer[0] != '\0' )
+       {
+       envp[envn++] = build_env( "HTTP_REFERER=%s", hc->referrer );
+       envp[envn++] = build_env( "HTTP_REFERRER=%s", hc->referrer );
+       }
+    if ( hc->useragent[0] != '\0' )
+       envp[envn++] = build_env( "HTTP_USER_AGENT=%s", hc->useragent );
+    if ( hc->accept[0] != '\0' )
+       envp[envn++] = build_env( "HTTP_ACCEPT=%s", hc->accept );
+    if ( hc->accepte[0] != '\0' )
+       envp[envn++] = build_env( "HTTP_ACCEPT_ENCODING=%s", hc->accepte );
+    if ( hc->acceptl[0] != '\0' )
+       envp[envn++] = build_env( "HTTP_ACCEPT_LANGUAGE=%s", hc->acceptl );
+    if ( hc->cookie[0] != '\0' )
+       envp[envn++] = build_env( "HTTP_COOKIE=%s", hc->cookie );
+    if ( hc->contenttype[0] != '\0' )
+       envp[envn++] = build_env( "CONTENT_TYPE=%s", hc->contenttype );
+    if ( hc->hdrhost[0] != '\0' )
+       envp[envn++] = build_env( "HTTP_HOST=%s", hc->hdrhost );
+    if ( hc->contentlength != -1 )
+       {
+       (void) my_snprintf(
+           buf, sizeof(buf), "%lu", (unsigned long) hc->contentlength );
+       envp[envn++] = build_env( "CONTENT_LENGTH=%s", buf );
+       }
+    if ( hc->remoteuser[0] != '\0' )
+       envp[envn++] = build_env( "REMOTE_USER=%s", hc->remoteuser );
+    if ( hc->authorization[0] != '\0' )
+       envp[envn++] = build_env( "AUTH_TYPE=%s", "Basic" );
+       /* We only support Basic auth at the moment. */
+    if ( getenv( "TZ" ) != (char*) 0 )
+       envp[envn++] = build_env( "TZ=%s", getenv( "TZ" ) );
+    envp[envn++] = build_env( "CGI_PATTERN=%s", hc->hs->cgi_pattern );
+
+    envp[envn] = (char*) 0;
+    return envp;
+    }
+
+
+/* Set up argument vector.  Again, we don't have to worry about freeing stuff
+** since we're a sub-process.  This gets done after make_envp() because we
+** scribble on hc->query.
+*/
+static char**
+make_argp( httpd_conn* hc )
+    {
+    char** argp;
+    int argn;
+    char* cp1;
+    char* cp2;
+
+    /* By allocating an arg slot for every character in the query, plus
+    ** one for the filename and one for the NULL, we are guaranteed to
+    ** have enough.  We could actually use strlen/2.
+    */
+    argp = NEW( char*, strlen( hc->query ) + 2 );
+    if ( argp == (char**) 0 )
+       return (char**) 0;
+
+    argp[0] = strrchr( hc->expnfilename, '/' );
+    if ( argp[0] != (char*) 0 )
+       ++argp[0];
+    else
+       argp[0] = hc->expnfilename;
+
+    argn = 1;
+    /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html,
+    ** "The server should search the query information for a non-encoded =
+    ** character to determine if the command line is to be used, if it finds
+    ** one, the command line is not to be used."
+    */
+    if ( strchr( hc->query, '=' ) == (char*) 0 )
+       {
+       for ( cp1 = cp2 = hc->query; *cp2 != '\0'; ++cp2 )
+           {
+           if ( *cp2 == '+' )
+               {
+               *cp2 = '\0';
+               strdecode( cp1, cp1 );
+               argp[argn++] = cp1;
+               cp1 = cp2 + 1;
+               }
+           }
+       if ( cp2 != cp1 )
+           {
+           strdecode( cp1, cp1 );
+           argp[argn++] = cp1;
+           }
+       }
+
+    argp[argn] = (char*) 0;
+    return argp;
+    }
+
+
+/* This routine is used only for POST requests.  It reads the data
+** from the request and sends it to the child process.  The only reason
+** we need to do it this way instead of just letting the child read
+** directly is that we have already read part of the data into our
+** buffer.
+*/
+static void
+cgi_interpose_input( httpd_conn* hc, int wfd )
+    {
+    size_t c;
+    ssize_t r;
+    char buf[1024];
+
+    c = hc->read_idx - hc->checked_idx;
+    if ( c > 0 )
+       {
+       if ( httpd_write_fully( wfd, &(hc->read_buf[hc->checked_idx]), c ) != c )
+           return;
+       }
+    while ( c < hc->contentlength )
+       {
+       r = read( hc->conn_fd, buf, MIN( sizeof(buf), hc->contentlength - c ) );
+       if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
+           {
+           sleep( 1 );
+           continue;
+           }
+       if ( r <= 0 )
+           return;
+       if ( httpd_write_fully( wfd, buf, r ) != r )
+           return;
+       c += r;
+       }
+    post_post_garbage_hack( hc );
+    }
+
+
+/* Special hack to deal with broken browsers that send a LF or CRLF
+** after POST data, causing TCP resets - we just read and discard up
+** to 2 bytes.  Unfortunately this doesn't fix the problem for CGIs
+** which avoid the interposer process due to their POST data being
+** short.  Creating an interposer process for all POST CGIs is
+** unacceptably expensive.  The eventual fix will come when interposing
+** gets integrated into the main loop as a tasklet instead of a process.
+*/
+static void
+post_post_garbage_hack( httpd_conn* hc )
+    {
+    char buf[2];
+
+    /* If we are in a sub-process, turn on no-delay mode in case we
+    ** previously cleared it.
+    */
+    if ( sub_process )
+       httpd_set_ndelay( hc->conn_fd );
+    /* And read up to 2 bytes. */
+    (void) read( hc->conn_fd, buf, sizeof(buf) );
+    }
+
+
+/* This routine is used for parsed-header CGIs.  The idea here is that the
+** CGI can return special headers such as "Status:" and "Location:" which
+** change the return status of the response.  Since the return status has to
+** be the very first line written out, we have to accumulate all the headers
+** and check for the special ones before writing the status.  Then we write
+** out the saved headers and proceed to echo the rest of the response.
+*/
+static void
+cgi_interpose_output( httpd_conn* hc, int rfd )
+    {
+    int r;
+    char buf[1024];
+    size_t headers_size, headers_len;
+    char* headers;
+    char* br;
+    int status;
+    char* title;
+    char* cp;
+
+    /* Make sure the connection is in blocking mode.  It should already
+    ** be blocking, but we might as well be sure.
+    */
+    httpd_clear_ndelay( hc->conn_fd );
+
+    /* Slurp in all headers. */
+    headers_size = 0;
+    httpd_realloc_str( &headers, &headers_size, 500 );
+    headers_len = 0;
+    for (;;)
+       {
+       r = read( rfd, buf, sizeof(buf) );
+       if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
+           {
+           sleep( 1 );
+           continue;
+           }
+       if ( r <= 0 )
+           {
+           br = &(headers[headers_len]);
+           break;
+           }
+       httpd_realloc_str( &headers, &headers_size, headers_len + r );
+       (void) memmove( &(headers[headers_len]), buf, r );
+       headers_len += r;
+       headers[headers_len] = '\0';
+       if ( ( br = strstr( headers, "\015\012\015\012" ) ) != (char*) 0 ||
+            ( br = strstr( headers, "\012\012" ) ) != (char*) 0 )
+           break;
+       }
+
+    /* If there were no headers, bail. */
+    if ( headers[0] == '\0' )
+       return;
+
+    /* Figure out the status.  Look for a Status: or Location: header;
+    ** else if there's an HTTP header line, get it from there; else
+    ** default to 200.
+    */
+    status = 200;
+    if ( strncmp( headers, "HTTP/", 5 ) == 0 )
+       {
+       cp = headers;
+       cp += strcspn( cp, " \t" );
+       status = atoi( cp );
+       }
+    if ( ( cp = strstr( headers, "Location:" ) ) != (char*) 0 &&
+        cp < br &&
+        ( cp == headers || *(cp-1) == '\012' ) )
+       status = 302;
+    if ( ( cp = strstr( headers, "Status:" ) ) != (char*) 0 &&
+        cp < br &&
+        ( cp == headers || *(cp-1) == '\012' ) )
+       {
+       cp += 7;
+       cp += strspn( cp, " \t" );
+       status = atoi( cp );
+       }
+
+    /* Write the status line. */
+    switch ( status )
+       {
+       case 200: title = ok200title; break;
+       case 302: title = err302title; break;
+       case 304: title = err304title; break;
+       case 400: title = httpd_err400title; break;
+#ifdef AUTH_FILE
+       case 401: title = err401title; break;
+#endif /* AUTH_FILE */
+       case 403: title = err403title; break;
+       case 404: title = err404title; break;
+       case 408: title = httpd_err408title; break;
+       case 451: title = err451title; break;
+       case 500: title = err500title; break;
+       case 501: title = err501title; break;
+       case 503: title = httpd_err503title; break;
+       default: title = "Something"; break;
+       }
+    (void) my_snprintf( buf, sizeof(buf), "HTTP/1.0 %d %s\015\012", status, title );
+    (void) httpd_write_fully( hc->conn_fd, buf, strlen( buf ) );
+
+    /* Write the saved headers. */
+    (void) httpd_write_fully( hc->conn_fd, headers, headers_len );
+
+    /* Echo the rest of the output. */
+    for (;;)
+       {
+       r = read( rfd, buf, sizeof(buf) );
+       if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
+           {
+           sleep( 1 );
+           continue;
+           }
+       if ( r <= 0 )
+           break;
+       if ( httpd_write_fully( hc->conn_fd, buf, r ) != r )
+           break;
+       }
+    shutdown( hc->conn_fd, SHUT_WR );
+    }
+
+
+/* CGI child process. */
+static void
+cgi_child( httpd_conn* hc )
+    {
+    int r;
+    char** argp;
+    char** envp;
+    char* binary;
+    char* directory;
+
+    /* Unset close-on-exec flag for this socket.  This actually shouldn't
+    ** be necessary, according to POSIX a dup()'d file descriptor does
+    ** *not* inherit the close-on-exec flag, its flag is always clear.
+    ** However, Linux messes this up and does copy the flag to the
+    ** dup()'d descriptor, so we have to clear it.  This could be
+    ** ifdeffed for Linux only.
+    */
+    (void) fcntl( hc->conn_fd, F_SETFD, 0 );
+
+    /* Close the syslog descriptor so that the CGI program can't
+    ** mess with it.  All other open descriptors should be either
+    ** the listen socket(s), sockets from accept(), or the file-logging
+    ** fd, and all of those are set to close-on-exec, so we don't
+    ** have to close anything else.
+    */
+    closelog();
+
+    /* If the socket happens to be using one of the stdin/stdout/stderr
+    ** descriptors, move it to another descriptor so that the dup2 calls
+    ** below don't screw things up.  We arbitrarily pick fd 3 - if there
+    ** was already something on it, we clobber it, but that doesn't matter
+    ** since at this point the only fd of interest is the connection.
+    ** All others will be closed on exec.
+    */
+    if ( hc->conn_fd == STDIN_FILENO || hc->conn_fd == STDOUT_FILENO || hc->conn_fd == STDERR_FILENO )
+       {
+       int newfd = dup2( hc->conn_fd, STDERR_FILENO + 1 );
+       if ( newfd >= 0 )
+           hc->conn_fd = newfd;
+       /* If the dup2 fails, shrug.  We'll just take our chances.
+       ** Shouldn't happen though.
+       */
+       }
+
+    /* Make the environment vector. */
+    envp = make_envp( hc );
+
+    /* Make the argument vector. */
+    argp = make_argp( hc );
+
+    /* Set up stdin.  For POSTs we may have to set up a pipe from an
+    ** interposer process, depending on if we've read some of the data
+    ** into our buffer.
+    */
+    if ( hc->method == METHOD_POST && hc->read_idx > hc->checked_idx )
+       {
+       int p[2];
+
+       if ( pipe( p ) < 0 )
+           {
+           syslog( LOG_ERR, "pipe - %m" );
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           httpd_write_response( hc );
+           exit( 1 );
+           }
+       r = fork( );
+       if ( r < 0 )
+           {
+           syslog( LOG_ERR, "fork - %m" );
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           httpd_write_response( hc );
+           exit( 1 );
+           }
+       if ( r == 0 )
+           {
+           /* Interposer process. */
+           sub_process = 1;
+           (void) close( p[0] );
+           cgi_interpose_input( hc, p[1] );
+           exit( 0 );
+           }
+       /* Need to schedule a kill for process r; but in the main process! */
+       (void) close( p[1] );
+       if ( p[0] != STDIN_FILENO )
+           {
+           (void) dup2( p[0], STDIN_FILENO );
+           (void) close( p[0] );
+           }
+       }
+    else
+       {
+       /* Otherwise, the request socket is stdin. */
+       if ( hc->conn_fd != STDIN_FILENO )
+           (void) dup2( hc->conn_fd, STDIN_FILENO );
+       }
+
+    /* Set up stdout/stderr.  If we're doing CGI header parsing,
+    ** we need an output interposer too.
+    */
+    if ( strncmp( argp[0], "nph-", 4 ) != 0 && hc->mime_flag )
+       {
+       int p[2];
+
+       if ( pipe( p ) < 0 )
+           {
+           syslog( LOG_ERR, "pipe - %m" );
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           httpd_write_response( hc );
+           exit( 1 );
+           }
+       r = fork( );
+       if ( r < 0 )
+           {
+           syslog( LOG_ERR, "fork - %m" );
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           httpd_write_response( hc );
+           exit( 1 );
+           }
+       if ( r == 0 )
+           {
+           /* Interposer process. */
+           sub_process = 1;
+           (void) close( p[1] );
+           cgi_interpose_output( hc, p[0] );
+           exit( 0 );
+           }
+       /* Need to schedule a kill for process r; but in the main process! */
+       (void) close( p[0] );
+       if ( p[1] != STDOUT_FILENO )
+           (void) dup2( p[1], STDOUT_FILENO );
+       if ( p[1] != STDERR_FILENO )
+           (void) dup2( p[1], STDERR_FILENO );
+       if ( p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO )
+           (void) close( p[1] );
+       }
+    else
+       {
+       /* Otherwise, the request socket is stdout/stderr. */
+       if ( hc->conn_fd != STDOUT_FILENO )
+           (void) dup2( hc->conn_fd, STDOUT_FILENO );
+       if ( hc->conn_fd != STDERR_FILENO )
+           (void) dup2( hc->conn_fd, STDERR_FILENO );
+       }
+
+    /* At this point we would like to set close-on-exec again for hc->conn_fd
+    ** (see previous comments on Linux's broken behavior re: close-on-exec
+    ** and dup.)  Unfortunately there seems to be another Linux problem, or
+    ** perhaps a different aspect of the same problem - if we do this
+    ** close-on-exec in Linux, the socket stays open but stderr gets
+    ** closed - the last fd duped from the socket.  What a mess.  So we'll
+    ** just leave the socket as is, which under other OSs means an extra
+    ** file descriptor gets passed to the child process.  Since the child
+    ** probably already has that file open via stdin stdout and/or stderr,
+    ** this is not a problem.
+    */
+    /* (void) fcntl( hc->conn_fd, F_SETFD, 1 ); */
+
+#ifdef CGI_NICE
+    /* Set priority. */
+    (void) nice( CGI_NICE );
+#endif /* CGI_NICE */
+
+    /* Split the program into directory and binary, so we can chdir()
+    ** to the program's own directory.  This isn't in the CGI 1.1
+    ** spec, but it's what other HTTP servers do.
+    */
+    directory = strdup( hc->expnfilename );
+    if ( directory == (char*) 0 )
+       binary = hc->expnfilename;      /* ignore errors */
+    else
+       {
+       binary = strrchr( directory, '/' );
+       if ( binary == (char*) 0 )
+           binary = hc->expnfilename;
+       else
+           {
+           *binary++ = '\0';
+           (void) chdir( directory );  /* ignore errors */
+           }
+       }
+
+    /* Default behavior for SIGPIPE. */
+#ifdef HAVE_SIGSET
+    (void) sigset( SIGPIPE, SIG_DFL );
+#else /* HAVE_SIGSET */
+    (void) signal( SIGPIPE, SIG_DFL );
+#endif /* HAVE_SIGSET */
+
+    /* Run the program. */
+    (void) execve( binary, argp, envp );
+
+    /* Something went wrong. */
+    syslog( LOG_ERR, "execve %.80s - %m", hc->expnfilename );
+    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+    httpd_write_response( hc );
+    _exit( 1 );
+    }
+
+
+static int
+cgi( httpd_conn* hc )
+    {
+    int r;
+    ClientData client_data;
+
+    if ( hc->hs->cgi_limit != 0 && hc->hs->cgi_count >= hc->hs->cgi_limit )
+       {
+       httpd_send_err(
+           hc, 503, httpd_err503title, "", httpd_err503form,
+           hc->encodedurl );
+       return -1;
+       }
+    ++hc->hs->cgi_count;
+    httpd_clear_ndelay( hc->conn_fd );
+    r = fork( );
+    if ( r < 0 )
+       {
+       syslog( LOG_ERR, "fork - %m" );
+       httpd_send_err(
+           hc, 500, err500title, "", err500form, hc->encodedurl );
+       return -1;
+       }
+    if ( r == 0 )
+       {
+       /* Child process. */
+       sub_process = 1;
+       httpd_unlisten( hc->hs );
+       cgi_child( hc );
+       }
+
+    /* Parent process. */
+    syslog( LOG_DEBUG, "spawned CGI process %d for file '%.200s'", r, hc->expnfilename );
+#ifdef CGI_TIMELIMIT
+    /* Schedule a kill for the child process, in case it runs too long */
+    client_data.i = r;
+    if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 )
+       {
+       syslog( LOG_CRIT, "tmr_create(cgi_kill child) failed" );
+       exit( 1 );
+       }
+#endif /* CGI_TIMELIMIT */
+    hc->status = 200;
+    hc->bytes_sent = CGI_BYTECOUNT;
+    hc->should_linger = 0;
+
+    return 0;
+    }
+
+
+static int
+really_start_request( httpd_conn* hc, struct timeval* nowP )
+    {
+    static char* indexname;
+    static size_t maxindexname = 0;
+    static const char* index_names[] = { INDEX_NAMES };
+    int i;
+#ifdef AUTH_FILE
+    static char* dirname;
+    static size_t maxdirname = 0;
+#endif /* AUTH_FILE */
+    size_t expnlen, indxlen;
+    char* cp;
+    char* pi;
+
+    expnlen = strlen( hc->expnfilename );
+
+    /* Stat the file. */
+    if ( stat( hc->expnfilename, &hc->sb ) < 0 )
+       {
+       httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+       return -1;
+       }
+
+    /* Is it world-readable or world-executable?  We check explicitly instead
+    ** of just trying to open it, so that no one ever gets surprised by
+    ** a file that's not set world-readable and yet somehow is
+    ** readable by the HTTP server and therefore the *whole* world.
+    */
+    if ( ! ( hc->sb.st_mode & ( S_IROTH | S_IXOTH ) ) )
+       {
+       syslog(
+           LOG_INFO,
+           "%.80s URL \"%.80s\" resolves to a non world-readable file",
+           httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file that is not world-readable.\n" ),
+           hc->encodedurl );
+       return -1;
+       }
+
+    /* Is it a directory? */
+    if ( S_ISDIR(hc->sb.st_mode) )
+       {
+       /* If there's pathinfo, it's just a non-existent file. */
+       if ( hc->pathinfo[0] != '\0' )
+           {
+           httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl );
+           return -1;
+           }
+
+       /* Special handling for directory URLs that don't end in a slash.
+       ** We send back an explicit redirect with the slash, because
+       ** otherwise many clients can't build relative URLs properly.
+       */
+       if ( strcmp( hc->origfilename, "" ) != 0 &&
+            strcmp( hc->origfilename, "." ) != 0 &&
+            hc->origfilename[strlen( hc->origfilename ) - 1] != '/' )
+           {
+           send_dirredirect( hc );
+           return -1;
+           }
+
+       /* Check for an index file. */
+       for ( i = 0; i < sizeof(index_names) / sizeof(char*); ++i )
+           {
+           httpd_realloc_str(
+               &indexname, &maxindexname,
+               expnlen + 1 + strlen( index_names[i] ) );
+           (void) strcpy( indexname, hc->expnfilename );
+           indxlen = strlen( indexname );
+           if ( indxlen == 0 || indexname[indxlen - 1] != '/' )
+               (void) strcat( indexname, "/" );
+           if ( strcmp( indexname, "./" ) == 0 )
+               indexname[0] = '\0';
+           (void) strcat( indexname, index_names[i] );
+           if ( stat( indexname, &hc->sb ) >= 0 )
+               goto got_one;
+           }
+
+       /* Nope, no index file, so it's an actual directory request. */
+#ifdef GENERATE_INDEXES
+       /* Directories must be readable for indexing. */
+       if ( ! ( hc->sb.st_mode & S_IROTH ) )
+           {
+           syslog(
+               LOG_INFO,
+               "%.80s URL \"%.80s\" tried to index a directory with indexing disabled",
+               httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+           httpd_send_err(
+               hc, 403, err403title, "",
+               ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a directory that has indexing disabled.\n" ),
+               hc->encodedurl );
+           return -1;
+           }
+#ifdef AUTH_FILE
+       /* Check authorization for this directory. */
+       if ( auth_check( hc, hc->expnfilename ) == -1 )
+           return -1;
+#endif /* AUTH_FILE */
+       /* Referrer check. */
+       if ( ! check_referrer( hc ) )
+           return -1;
+       /* Ok, generate an index. */
+       return ls( hc );
+#else /* GENERATE_INDEXES */
+       syslog(
+           LOG_INFO, "%.80s URL \"%.80s\" tried to index a directory",
+           httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "The requested URL '%.80s' is a directory, and directory indexing is disabled on this server.\n" ),
+           hc->encodedurl );
+       return -1;
+#endif /* GENERATE_INDEXES */
+
+       got_one: ;
+       /* Got an index file.  Expand symlinks again.  More pathinfo means
+       ** something went wrong.
+       */
+       cp = expand_symlinks( indexname, &pi, hc->hs->no_symlink_check, hc->tildemapped );
+       if ( cp == (char*) 0 || pi[0] != '\0' )
+           {
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           return -1;
+           }
+       expnlen = strlen( cp );
+       httpd_realloc_str( &hc->expnfilename, &hc->maxexpnfilename, expnlen );
+       (void) strcpy( hc->expnfilename, cp );
+
+       /* Now, is the index version world-readable or world-executable? */
+       if ( ! ( hc->sb.st_mode & ( S_IROTH | S_IXOTH ) ) )
+           {
+           syslog(
+               LOG_INFO,
+               "%.80s URL \"%.80s\" resolves to a non-world-readable index file",
+               httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+           httpd_send_err(
+               hc, 403, err403title, "",
+               ERROR_FORM( err403form, "The requested URL '%.80s' resolves to an index file that is not world-readable.\n" ),
+               hc->encodedurl );
+           return -1;
+           }
+       }
+
+#ifdef AUTH_FILE
+    /* Check authorization for this directory. */
+    httpd_realloc_str( &dirname, &maxdirname, expnlen );
+    (void) strcpy( dirname, hc->expnfilename );
+    cp = strrchr( dirname, '/' );
+    if ( cp == (char*) 0 )
+       (void) strcpy( dirname, "." );
+    else
+       *cp = '\0';
+    if ( auth_check( hc, dirname ) == -1 )
+       return -1;
+
+    /* Check if the filename is the AUTH_FILE itself - that's verboten. */
+    if ( expnlen == sizeof(AUTH_FILE) - 1 )
+       {
+       if ( strcmp( hc->expnfilename, AUTH_FILE ) == 0 )
+           {
+           syslog(
+               LOG_NOTICE,
+               "%.80s URL \"%.80s\" tried to retrieve an auth file",
+               httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+           httpd_send_err(
+               hc, 403, err403title, "",
+               ERROR_FORM( err403form, "The requested URL '%.80s' is an authorization file, retrieving it is not permitted.\n" ),
+               hc->encodedurl );
+           return -1;
+           }
+       }
+    else if ( expnlen >= sizeof(AUTH_FILE) &&
+             strcmp( &(hc->expnfilename[expnlen - sizeof(AUTH_FILE) + 1]), AUTH_FILE ) == 0 &&
+             hc->expnfilename[expnlen - sizeof(AUTH_FILE)] == '/' )
+       {
+       syslog(
+           LOG_NOTICE,
+           "%.80s URL \"%.80s\" tried to retrieve an auth file",
+           httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "The requested URL '%.80s' is an authorization file, retrieving it is not permitted.\n" ),
+           hc->encodedurl );
+       return -1;
+       }
+#endif /* AUTH_FILE */
+
+    /* Referrer check. */
+    if ( ! check_referrer( hc ) )
+       return -1;
+
+    /* Is it world-executable and in the CGI area? */
+    if ( hc->hs->cgi_pattern != (char*) 0 &&
+        ( hc->sb.st_mode & S_IXOTH ) &&
+        match( hc->hs->cgi_pattern, hc->expnfilename ) )
+       return cgi( hc );
+
+    /* It's not CGI.  If it's executable or there's pathinfo, someone's
+    ** trying to either serve or run a non-CGI file as CGI.   Either case
+    ** is prohibited.
+    */
+    if ( hc->sb.st_mode & S_IXOTH )
+       {
+       syslog(
+           LOG_NOTICE, "%.80s URL \"%.80s\" is executable but isn't CGI",
+           httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file which is marked executable but is not a CGI file; retrieving it is forbidden.\n" ),
+           hc->encodedurl );
+       return -1;
+       }
+    if ( hc->pathinfo[0] != '\0' )
+       {
+       syslog(
+           LOG_INFO, "%.80s URL \"%.80s\" has pathinfo but isn't CGI",
+           httpd_ntoa( &hc->client_addr ), hc->encodedurl );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file plus CGI-style pathinfo, but the file is not a valid CGI file.\n" ),
+           hc->encodedurl );
+       return -1;
+       }
+
+    if ( hc->method != METHOD_GET && hc->method != METHOD_HEAD )
+       {
+       httpd_send_err(
+           hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) );
+       return -1;
+       }
+
+    /* Fill in last_byte_index, if necessary. */
+    if ( hc->got_range &&
+        ( hc->last_byte_index == -1 || hc->last_byte_index >= hc->sb.st_size ) )
+       hc->last_byte_index = hc->sb.st_size - 1;
+
+    figure_mime( hc );
+
+    if ( hc->method == METHOD_HEAD )
+       {
+       send_mime(
+           hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size,
+           hc->sb.st_mtime );
+       }
+    else if ( hc->if_modified_since != (time_t) -1 &&
+        hc->if_modified_since >= hc->sb.st_mtime )
+       {
+       send_mime(
+           hc, 304, err304title, hc->encodings, "", hc->type, (off_t) -1,
+           hc->sb.st_mtime );
+       }
+    else
+       {
+       hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP );
+       if ( hc->file_address == (char*) 0 )
+           {
+           httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+           return -1;
+           }
+       send_mime(
+           hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size,
+           hc->sb.st_mtime );
+       }
+
+    return 0;
+    }
+
+
+int
+httpd_start_request( httpd_conn* hc, struct timeval* nowP )
+    {
+    int r;
+
+    /* Really start the request. */
+    r = really_start_request( hc, nowP );
+
+    /* And return the status. */
+    return r;
+    }
+
+
+static void
+make_log_entry( httpd_conn* hc, struct timeval* nowP )
+    {
+    char* ru;
+    char url[305];
+    char bytes[40];
+
+    if ( hc->hs->no_log )
+       return;
+
+    /* This is straight CERN Combined Log Format - the only tweak
+    ** being that if we're using syslog() we leave out the date, because
+    ** syslogd puts it in.  The included syslogtocern script turns the
+    ** results into true CERN format.
+    */
+
+    /* Format remote user. */
+    if ( hc->remoteuser[0] != '\0' )
+       ru = hc->remoteuser;
+    else
+       ru = "-";
+    /* If we're vhosting, prepend the hostname to the url.  This is
+    ** a little weird, perhaps writing separate log files for
+    ** each vhost would make more sense.
+    */
+    if ( hc->hs->vhost && ! hc->tildemapped )
+       (void) my_snprintf( url, sizeof(url),
+           "/%.100s%.200s",
+           hc->hostname == (char*) 0 ? hc->hs->server_hostname : hc->hostname,
+           hc->encodedurl );
+    else
+       (void) my_snprintf( url, sizeof(url),
+           "%.200s", hc->encodedurl );
+    /* Format the bytes. */
+    if ( hc->bytes_sent >= 0 )
+       (void) my_snprintf(
+           bytes, sizeof(bytes), "%lld", (long long) hc->bytes_sent );
+    else
+       (void) strcpy( bytes, "-" );
+
+    /* Logfile or syslog? */
+    if ( hc->hs->logfp != (FILE*) 0 )
+       {
+       time_t now;
+       struct tm* t;
+       const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
+       char date_nozone[100];
+       int zone;
+       char sign;
+       char date[100];
+
+       /* Get the current time, if necessary. */
+       if ( nowP != (struct timeval*) 0 )
+           now = nowP->tv_sec;
+       else
+           now = time( (time_t*) 0 );
+       /* Format the time, forcing a numeric timezone (some log analyzers
+       ** are stoooopid about this).
+       */
+       t = localtime( &now );
+       (void) strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t );
+#ifdef HAVE_TM_GMTOFF
+       zone = t->tm_gmtoff / 60L;
+#else
+       zone = -timezone / 60L;
+       /* Probably have to add something about daylight time here. */
+#endif
+       if ( zone >= 0 )
+           sign = '+';
+       else
+           {
+           sign = '-';
+           zone = -zone;
+           }
+       zone = ( zone / 60 ) * 100 + zone % 60;
+       (void) my_snprintf( date, sizeof(date),
+           "%s %c%04d", date_nozone, sign, zone );
+       /* And write the log entry. */
+       (void) fprintf( hc->hs->logfp,
+           "%.80s - %.80s [%s] \"%.80s %.300s %.80s\" %d %s \"%.200s\" \"%.200s\"\n",
+           httpd_ntoa( &hc->client_addr ), ru, date,
+           httpd_method_str( hc->method ), url, hc->protocol,
+           hc->status, bytes, hc->referrer, hc->useragent );
+#ifdef FLUSH_LOG_EVERY_TIME
+       (void) fflush( hc->hs->logfp );
+#endif
+       }
+    else
+       syslog( LOG_INFO,
+           "%.80s - %.80s \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.200s\"",
+           httpd_ntoa( &hc->client_addr ), ru,
+           httpd_method_str( hc->method ), url, hc->protocol,
+           hc->status, bytes, hc->referrer, hc->useragent );
+    }
+
+
+/* Returns 1 if ok to serve the url, 0 if not. */
+static int
+check_referrer( httpd_conn* hc )
+    {
+    int r;
+    char* cp;
+
+    /* Are we doing referrer checking at all? */
+    if ( hc->hs->url_pattern == (char*) 0 )
+       return 1;
+
+    r = really_check_referrer( hc );
+
+    if ( ! r )
+       {
+       if ( hc->hs->vhost && hc->hostname != (char*) 0 )
+           cp = hc->hostname;
+       else
+           cp = hc->hs->server_hostname;
+       if ( cp == (char*) 0 )
+           cp = "";
+       syslog(
+           LOG_INFO, "%.80s non-local referrer \"%.80s%.80s\" \"%.80s\"",
+           httpd_ntoa( &hc->client_addr ), cp, hc->encodedurl, hc->referrer );
+       httpd_send_err(
+           hc, 403, err403title, "",
+           ERROR_FORM( err403form, "You must supply a local referrer to get URL '%.80s' from this server.\n" ),
+           hc->encodedurl );
+       }
+    return r;
+    }
+
+
+/* Returns 1 if ok to serve the url, 0 if not. */
+static int
+really_check_referrer( httpd_conn* hc )
+    {
+    httpd_server* hs;
+    char* cp1;
+    char* cp2;
+    char* cp3;
+    static char* refhost = (char*) 0;
+    static size_t refhost_size = 0;
+    char *lp;
+
+    hs = hc->hs;
+
+    /* Check for an empty referrer. */
+    if ( hc->referrer == (char*) 0 || hc->referrer[0] == '\0' ||
+        ( cp1 = strstr( hc->referrer, "//" ) ) == (char*) 0 )
+       {
+       /* Disallow if we require a referrer and the url matches. */
+       if ( hs->no_empty_referrers && match( hs->url_pattern, hc->origfilename ) )
+           return 0;
+       /* Otherwise ok. */
+       return 1;
+       }
+
+    /* Extract referrer host. */
+    cp1 += 2;
+    for ( cp2 = cp1; *cp2 != '/' && *cp2 != ':' && *cp2 != '\0'; ++cp2 )
+       continue;
+    httpd_realloc_str( &refhost, &refhost_size, cp2 - cp1 );
+    for ( cp3 = refhost; cp1 < cp2; ++cp1, ++cp3 )
+       if ( isupper(*cp1) )
+           *cp3 = tolower(*cp1);
+       else
+           *cp3 = *cp1;
+    *cp3 = '\0';
+
+    /* Local pattern? */
+    if ( hs->local_pattern != (char*) 0 )
+       lp = hs->local_pattern;
+    else
+       {
+       /* No local pattern.  What's our hostname? */
+       if ( ! hs->vhost )
+           {
+           /* Not vhosting, use the server name. */
+           lp = hs->server_hostname;
+           if ( lp == (char*) 0 )
+               /* Couldn't figure out local hostname - give up. */
+               return 1;
+           }
+       else
+           {
+           /* We are vhosting, use the hostname on this connection. */
+           lp = hc->hostname;
+           if ( lp == (char*) 0 )
+               /* Oops, no hostname.  Maybe it's an old browser that
+               ** doesn't send a Host: header.  We could figure out
+               ** the default hostname for this IP address, but it's
+               ** not worth it for the few requests like this.
+               */
+               return 1;
+           }
+       }
+
+    /* If the referrer host doesn't match the local host pattern, and
+    ** the filename does match the url pattern, it's an illegal reference.
+    */
+    if ( ! match( lp, refhost ) && match( hs->url_pattern, hc->origfilename ) )
+       return 0;
+    /* Otherwise ok. */
+    return 1;
+    }
+
+
+char*
+httpd_ntoa( httpd_sockaddr* saP )
+    {
+#ifdef USE_IPV6
+    static char str[200];
+
+    if ( getnameinfo( &saP->sa, sockaddr_len( saP ), str, sizeof(str), 0, 0, NI_NUMERICHOST ) != 0 )
+       {
+       str[0] = '?';
+       str[1] = '\0';
+       }
+    else if ( IN6_IS_ADDR_V4MAPPED( &saP->sa_in6.sin6_addr ) && strncmp( str, "::ffff:", 7 ) == 0 )
+       /* Elide IPv6ish prefix for IPv4 addresses. */
+       (void) ol_strcpy( str, &str[7] );
+
+    return str;
+
+#else /* USE_IPV6 */
+
+    return inet_ntoa( saP->sa_in.sin_addr );
+
+#endif /* USE_IPV6 */
+    }
+
+
+static int
+sockaddr_check( httpd_sockaddr* saP )
+    {
+    switch ( saP->sa.sa_family )
+       {
+       case AF_INET: return 1;
+#ifdef USE_IPV6
+       case AF_INET6: return 1;
+#endif /* USE_IPV6 */
+       default:
+       return 0;
+       }
+    }
+
+
+static size_t
+sockaddr_len( httpd_sockaddr* saP )
+    {
+    switch ( saP->sa.sa_family )
+       {
+       case AF_INET: return sizeof(struct sockaddr_in);
+#ifdef USE_IPV6
+       case AF_INET6: return sizeof(struct sockaddr_in6);
+#endif /* USE_IPV6 */
+       default:
+       return 0;       /* shouldn't happen */
+       }
+    }
+
+
+/* Some systems don't have snprintf(), so we make our own that uses
+** either vsnprintf() or vsprintf().  If your system doesn't have
+** vsnprintf(), it is probably vulnerable to buffer overruns.
+** Upgrade!
+*/
+static int
+my_snprintf( char* str, size_t size, const char* format, ... )
+    {
+    va_list ap;
+    int r;
+
+    va_start( ap, format );
+#ifdef HAVE_VSNPRINTF
+    r = vsnprintf( str, size, format, ap );
+#else /* HAVE_VSNPRINTF */
+    r = vsprintf( str, format, ap );
+#endif /* HAVE_VSNPRINTF */
+    va_end( ap );
+    return r;
+    }
+
+
+#ifndef HAVE_ATOLL
+static long long
+atoll( const char* str )
+    {
+    long long value;
+    long long sign;
+
+    while ( isspace( *str ) )
+       ++str;
+    switch ( *str )
+       {
+       case '-': sign = -1; ++str; break;
+       case '+': sign = 1; ++str; break;
+       default: sign = 1; break;
+       }
+    value = 0;
+    while ( isdigit( *str ) )
+       {
+       value = value * 10 + ( *str - '0' );
+       ++str;
+       }
+    return sign * value;
+    }
+#endif /* HAVE_ATOLL */
+
+
+/* Read the requested buffer completely, accounting for interruptions. */
+int
+httpd_read_fully( int fd, void* buf, size_t nbytes )
+    {
+    int nread;
+
+    nread = 0;
+    while ( nread < nbytes )
+       {
+       int r;
+
+       r = read( fd, (char*) buf + nread, nbytes - nread );
+       if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
+           {
+           sleep( 1 );
+           continue;
+           }
+       if ( r < 0 )
+           return r;
+       if ( r == 0 )
+           break;
+       nread += r;
+       }
+
+    return nread;
+    }
+
+
+/* Write the requested buffer completely, accounting for interruptions. */
+int
+httpd_write_fully( int fd, const char* buf, size_t nbytes )
+    {
+    int nwritten;
+
+    nwritten = 0;
+    while ( nwritten < nbytes )
+       {
+       int r;
+
+       r = write( fd, buf + nwritten, nbytes - nwritten );
+       if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
+           {
+           sleep( 1 );
+           continue;
+           }
+       if ( r < 0 )
+           return r;
+       if ( r == 0 )
+           break;
+       nwritten += r;
+       }
+
+    return nwritten;
+    }
+
+
+/* Generate debugging statistics syslog message. */
+void
+httpd_logstats( long secs )
+    {
+    if ( str_alloc_count > 0 )
+       syslog( LOG_NOTICE,
+           "  libhttpd - %d strings allocated, %lu bytes (%g bytes/str)",
+           str_alloc_count, (unsigned long) str_alloc_size,
+           (float) str_alloc_size / str_alloc_count );
+    }
diff --git a/libhttpd.h b/libhttpd.h
new file mode 100644 (file)
index 0000000..e707bc7
--- /dev/null
@@ -0,0 +1,291 @@
+/* libhttpd.h - defines for libhttpd
+**
+** Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _LIBHTTPD_H_
+#define _LIBHTTPD_H_
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
+#define USE_IPV6
+#endif
+
+
+/* A few convenient defines. */
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#define NEW(t,n) ((t*) malloc( sizeof(t) * (n) ))
+#define RENEW(o,t,n) ((t*) realloc( (void*) o, sizeof(t) * (n) ))
+
+/* Do overlapping strcpy safely, by using memmove. */
+#define ol_strcpy(dst,src) memmove(dst,src,strlen(src)+1)
+
+
+/* The httpd structs. */
+
+/* A multi-family sockaddr. */
+typedef union {
+    struct sockaddr sa;
+    struct sockaddr_in sa_in;
+#ifdef USE_IPV6
+    struct sockaddr_in6 sa_in6;
+    struct sockaddr_storage sa_stor;
+#endif /* USE_IPV6 */
+    } httpd_sockaddr;
+
+/* A server. */
+typedef struct {
+    char* binding_hostname;
+    char* server_hostname;
+    unsigned short port;
+    char* cgi_pattern;
+    int cgi_limit, cgi_count;
+    char* charset;
+    char* p3p;
+    int max_age;
+    char* cwd;
+    int listen4_fd, listen6_fd;
+    int no_log;
+    FILE* logfp;
+    int no_symlink_check;
+    int vhost;
+    int global_passwd;
+    char* url_pattern;
+    char* local_pattern;
+    int no_empty_referrers;
+    } httpd_server;
+
+/* A connection. */
+typedef struct {
+    int initialized;
+    httpd_server* hs;
+    httpd_sockaddr client_addr;
+    char* read_buf;
+    size_t read_size, read_idx, checked_idx;
+    int checked_state;
+    int method;
+    int status;
+    off_t bytes_to_send;
+    off_t bytes_sent;
+    char* encodedurl;
+    char* decodedurl;
+    char* protocol;
+    char* origfilename;
+    char* expnfilename;
+    char* encodings;
+    char* pathinfo;
+    char* query;
+    char* referrer;
+    char* useragent;
+    char* accept;
+    char* accepte;
+    char* acceptl;
+    char* cookie;
+    char* contenttype;
+    char* reqhost;
+    char* hdrhost;
+    char* hostdir;
+    char* authorization;
+    char* remoteuser;
+    char* response;
+    size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings,
+       maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir,
+       maxremoteuser, maxresponse;
+#ifdef TILDE_MAP_2
+    char* altdir;
+    size_t maxaltdir;
+#endif /* TILDE_MAP_2 */
+    size_t responselen;
+    time_t if_modified_since, range_if;
+    size_t contentlength;
+    char* type;                /* not malloc()ed */
+    char* hostname;    /* not malloc()ed */
+    int mime_flag;
+    int one_one;       /* HTTP/1.1 or better */
+    int got_range;
+    int tildemapped;   /* this connection got tilde-mapped */
+    off_t first_byte_index, last_byte_index;
+    int keep_alive;
+    int should_linger;
+    struct stat sb;
+    int conn_fd;
+    char* file_address;
+    } httpd_conn;
+
+/* Methods. */
+#define METHOD_UNKNOWN 0
+#define METHOD_GET 1
+#define METHOD_HEAD 2
+#define METHOD_POST 3
+#define METHOD_PUT 4
+#define METHOD_DELETE 5
+#define METHOD_TRACE 6
+
+/* States for checked_state. */
+#define CHST_FIRSTWORD 0
+#define CHST_FIRSTWS 1
+#define CHST_SECONDWORD 2
+#define CHST_SECONDWS 3
+#define CHST_THIRDWORD 4
+#define CHST_THIRDWS 5
+#define CHST_LINE 6
+#define CHST_LF 7
+#define CHST_CR 8
+#define CHST_CRLF 9
+#define CHST_CRLFCR 10
+#define CHST_BOGUS 11
+
+
+/* Initializes.  Does the socket(), bind(), and listen().   Returns an
+** httpd_server* which includes a socket fd that you can select() on.
+** Return (httpd_server*) 0 on error.
+*/
+httpd_server* httpd_initialize(
+    char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P,
+    unsigned short port, char* cgi_pattern, int cgi_limit, char* charset,
+    char* p3p, int max_age, char* cwd, int no_log, FILE* logfp,
+    int no_symlink_check, int vhost, int global_passwd, char* url_pattern,
+    char* local_pattern, int no_empty_referrers );
+
+/* Change the log file. */
+void httpd_set_logfp( httpd_server* hs, FILE* logfp );
+
+/* Call to unlisten/close socket(s) listening for new connections. */
+void httpd_unlisten( httpd_server* hs );
+
+/* Call to shut down. */
+void httpd_terminate( httpd_server* hs );
+
+
+/* When a listen fd is ready to read, call this.  It does the accept() and
+** returns an httpd_conn* which includes the fd to read the request from and
+** write the response to.  Returns an indication of whether the accept()
+** failed, succeeded, or if there were no more connections to accept.
+**
+** In order to minimize malloc()s, the caller passes in the httpd_conn.
+** The caller is also responsible for setting initialized to zero before the
+** first call using each different httpd_conn.
+*/
+int httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc );
+#define GC_FAIL 0
+#define GC_OK 1
+#define GC_NO_MORE 2
+
+/* Checks whether the data in hc->read_buf constitutes a complete request
+** yet.  The caller reads data into hc->read_buf[hc->read_idx] and advances
+** hc->read_idx.  This routine checks what has been read so far, using
+** hc->checked_idx and hc->checked_state to keep track, and returns an
+** indication of whether there is no complete request yet, there is a
+** complete request, or there won't be a valid request due to a syntax error.
+*/
+int httpd_got_request( httpd_conn* hc );
+#define GR_NO_REQUEST 0
+#define GR_GOT_REQUEST 1
+#define GR_BAD_REQUEST 2
+
+/* Parses the request in hc->read_buf.  Fills in lots of fields in hc,
+** like the URL and the various headers.
+**
+** Returns -1 on error.
+*/
+int httpd_parse_request( httpd_conn* hc );
+
+/* Starts sending data back to the client.  In some cases (directories,
+** CGI programs), finishes sending by itself - in those cases, hc->file_fd
+** is <0.  If there is more data to be sent, then hc->file_fd is a file
+** descriptor for the file to send.  If you don't have a current timeval
+** handy just pass in 0.
+**
+** Returns -1 on error.
+*/
+int httpd_start_request( httpd_conn* hc, struct timeval* nowP );
+
+/* Actually sends any buffered response text. */
+void httpd_write_response( httpd_conn* hc );
+
+/* Call this to close down a connection and free the data.  A fine point,
+** if you fork() with a connection open you should still call this in the
+** parent process - the connection will stay open in the child.
+** If you don't have a current timeval handy just pass in 0.
+*/
+void httpd_close_conn( httpd_conn* hc, struct timeval* nowP );
+
+/* Call this to de-initialize a connection struct and *really* free the
+** mallocced strings.
+*/
+void httpd_destroy_conn( httpd_conn* hc );
+
+
+/* Send an error message back to the client. */
+void httpd_send_err(
+    httpd_conn* hc, int status, char* title, char* extraheads, char* form,
+    char* arg );
+
+/* Some error messages. */
+extern char* httpd_err400title;
+extern char* httpd_err400form;
+extern char* httpd_err408title;
+extern char* httpd_err408form;
+extern char* httpd_err503title;
+extern char* httpd_err503form;
+
+/* Generate a string representation of a method number. */
+char* httpd_method_str( int method );
+
+/* Reallocate a string. */
+void httpd_realloc_str( char** strP, size_t* maxsizeP, size_t size );
+
+/* Format a network socket to a string representation. */
+char* httpd_ntoa( httpd_sockaddr* saP );
+
+/* Set NDELAY mode on a socket. */
+void httpd_set_ndelay( int fd );
+
+/* Clear NDELAY mode on a socket. */
+void httpd_clear_ndelay( int fd );
+
+/* Read the requested buffer completely, accounting for interruptions. */
+int httpd_read_fully( int fd, void* buf, size_t nbytes );
+
+/* Write the requested buffer completely, accounting for interruptions. */
+int httpd_write_fully( int fd, const char* buf, size_t nbytes );
+
+/* Generate debugging statistics syslog message. */
+void httpd_logstats( long secs );
+
+#endif /* _LIBHTTPD_H_ */
diff --git a/libhttpd.o b/libhttpd.o
new file mode 100644 (file)
index 0000000..4746030
Binary files /dev/null and b/libhttpd.o differ
diff --git a/match.c b/match.c
new file mode 100644 (file)
index 0000000..6facccb
--- /dev/null
+++ b/match.c
@@ -0,0 +1,88 @@
+/* match.c - simple shell-style filename matcher
+**
+** Only does ? * and **, and multiple patterns separated by |.  Returns 1 or 0.
+**
+** Copyright © 1995,2000 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+
+#include <string.h>
+
+#include "match.h"
+
+static int match_one( const char* pattern, int patternlen, const char* string );
+
+int
+match( const char* pattern, const char* string )
+    {
+    const char* or;
+
+    for (;;)
+       {
+       or = strchr( pattern, '|' );
+       if ( or == (char*) 0 )
+           return match_one( pattern, strlen( pattern ), string );
+       if ( match_one( pattern, or - pattern, string ) )
+           return 1;
+       pattern = or + 1;
+       }
+    }
+
+
+static int
+match_one( const char* pattern, int patternlen, const char* string )
+    {
+    const char* p;
+
+    for ( p = pattern; p - pattern < patternlen; ++p, ++string )
+       {
+       if ( *p == '?' && *string != '\0' )
+           continue;
+       if ( *p == '*' )
+           {
+           int i, pl;
+           ++p;
+           if ( *p == '*' )
+               {
+               /* Double-wildcard matches anything. */
+               ++p;
+               i = strlen( string );
+               }
+           else
+               /* Single-wildcard matches anything but slash. */
+               i = strcspn( string, "/" );
+           pl = patternlen - ( p - pattern );
+           for ( ; i >= 0; --i )
+               if ( match_one( p, pl, &(string[i]) ) )
+                   return 1;
+           return 0;
+           }
+       if ( *p != *string )
+           return 0;
+       }
+    if ( *string == '\0' )
+       return 1;
+    return 0;
+    }
diff --git a/match.h b/match.h
new file mode 100644 (file)
index 0000000..01c5f2a
--- /dev/null
+++ b/match.h
@@ -0,0 +1,36 @@
+/* match.h - simple shell-style filename patcher
+**
+** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _MATCH_H_
+#define _MATCH_H_
+
+/* Simple shell-style filename pattern matcher.  Only does ? * and **, and
+** multiple patterns separated by |.  Returns 1 or 0.
+*/
+int match( const char* pattern, const char* string );
+
+#endif /* _MATCH_H_ */
diff --git a/match.o b/match.o
new file mode 100644 (file)
index 0000000..cc68349
Binary files /dev/null and b/match.o differ
diff --git a/mime_encodings.h b/mime_encodings.h
new file mode 100644 (file)
index 0000000..f12bd7f
--- /dev/null
@@ -0,0 +1,3 @@
+{ "Z", 0, "compress", 0 },
+{ "gz", 0, "gzip", 0 },
+{ "uu", 0, "x-uuencode", 0 },
diff --git a/mime_encodings.txt b/mime_encodings.txt
new file mode 100644 (file)
index 0000000..2d3952d
--- /dev/null
@@ -0,0 +1,8 @@
+# mime_encodings.txt
+#
+# A list of file extensions followed by the corresponding MIME encoding.
+# Extensions not found in the table proceed to the mime_types table.
+
+Z      compress
+gz     gzip
+uu     x-uuencode
diff --git a/mime_types.h b/mime_types.h
new file mode 100644 (file)
index 0000000..15a93fa
--- /dev/null
@@ -0,0 +1,193 @@
+{ "a", 0, "application/octet-stream", 0 },
+{ "aab", 0, "application/x-authorware-bin", 0 },
+{ "aam", 0, "application/x-authorware-map", 0 },
+{ "aas", 0, "application/x-authorware-seg", 0 },
+{ "ai", 0, "application/postscript", 0 },
+{ "aif", 0, "audio/x-aiff", 0 },
+{ "aifc", 0, "audio/x-aiff", 0 },
+{ "aiff", 0, "audio/x-aiff", 0 },
+{ "asc", 0, "text/plain; charset=%s", 0 },
+{ "asf", 0, "video/x-ms-asf", 0 },
+{ "asx", 0, "video/x-ms-asf", 0 },
+{ "au", 0, "audio/basic", 0 },
+{ "avi", 0, "video/x-msvideo", 0 },
+{ "bcpio", 0, "application/x-bcpio", 0 },
+{ "bin", 0, "application/octet-stream", 0 },
+{ "bmp", 0, "image/bmp", 0 },
+{ "cdf", 0, "application/x-netcdf", 0 },
+{ "class", 0, "application/x-java-vm", 0 },
+{ "cpio", 0, "application/x-cpio", 0 },
+{ "cpt", 0, "application/mac-compactpro", 0 },
+{ "crl", 0, "application/x-pkcs7-crl", 0 },
+{ "crt", 0, "application/x-x509-ca-cert", 0 },
+{ "csh", 0, "application/x-csh", 0 },
+{ "css", 0, "text/css; charset=%s", 0 },
+{ "dcr", 0, "application/x-director", 0 },
+{ "dir", 0, "application/x-director", 0 },
+{ "djv", 0, "image/vnd.djvu", 0 },
+{ "djvu", 0, "image/vnd.djvu", 0 },
+{ "dll", 0, "application/octet-stream", 0 },
+{ "dms", 0, "application/octet-stream", 0 },
+{ "doc", 0, "application/msword", 0 },
+{ "dtd", 0, "text/xml; charset=%s", 0 },
+{ "dump", 0, "application/octet-stream", 0 },
+{ "dvi", 0, "application/x-dvi", 0 },
+{ "dxr", 0, "application/x-director", 0 },
+{ "eps", 0, "application/postscript", 0 },
+{ "etx", 0, "text/x-setext", 0 },
+{ "exe", 0, "application/octet-stream", 0 },
+{ "ez", 0, "application/andrew-inset", 0 },
+{ "fgd", 0, "application/x-director", 0 },
+{ "fh", 0, "image/x-freehand", 0 },
+{ "fh4", 0, "image/x-freehand", 0 },
+{ "fh5", 0, "image/x-freehand", 0 },
+{ "fh7", 0, "image/x-freehand", 0 },
+{ "fhc", 0, "image/x-freehand", 0 },
+{ "gif", 0, "image/gif", 0 },
+{ "gtar", 0, "application/x-gtar", 0 },
+{ "hdf", 0, "application/x-hdf", 0 },
+{ "hqx", 0, "application/mac-binhex40", 0 },
+{ "htm", 0, "text/html; charset=%s", 0 },
+{ "html", 0, "text/html; charset=%s", 0 },
+{ "ice", 0, "x-conference/x-cooltalk", 0 },
+{ "ief", 0, "image/ief", 0 },
+{ "iges", 0, "model/iges", 0 },
+{ "igs", 0, "model/iges", 0 },
+{ "iv", 0, "application/x-inventor", 0 },
+{ "jar", 0, "application/x-java-archive", 0 },
+{ "jfif", 0, "image/jpeg", 0 },
+{ "jpe", 0, "image/jpeg", 0 },
+{ "jpeg", 0, "image/jpeg", 0 },
+{ "jpg", 0, "image/jpeg", 0 },
+{ "js", 0, "application/x-javascript", 0 },
+{ "kar", 0, "audio/midi", 0 },
+{ "kml", 0, "application/vnd.google-earth.kml+xml", 0 },
+{ "kmz", 0, "application/vnd.google-earth.kmz", 0 },
+{ "latex", 0, "application/x-latex", 0 },
+{ "lha", 0, "application/octet-stream", 0 },
+{ "loc", 0, "application/xml-loc", 0 },
+{ "lzh", 0, "application/octet-stream", 0 },
+{ "m3u", 0, "audio/x-mpegurl", 0 },
+{ "man", 0, "application/x-troff-man", 0 },
+{ "mathml", 0, "application/mathml+xml", 0 },
+{ "me", 0, "application/x-troff-me", 0 },
+{ "mesh", 0, "model/mesh", 0 },
+{ "mid", 0, "audio/midi", 0 },
+{ "midi", 0, "audio/midi", 0 },
+{ "mif", 0, "application/vnd.mif", 0 },
+{ "mime", 0, "message/rfc822", 0 },
+{ "mml", 0, "application/mathml+xml", 0 },
+{ "mov", 0, "video/quicktime", 0 },
+{ "movie", 0, "video/x-sgi-movie", 0 },
+{ "mp2", 0, "audio/mpeg", 0 },
+{ "mp3", 0, "audio/mpeg", 0 },
+{ "mp4", 0, "video/mp4", 0 },
+{ "mpe", 0, "video/mpeg", 0 },
+{ "mpeg", 0, "video/mpeg", 0 },
+{ "mpg", 0, "video/mpeg", 0 },
+{ "mpga", 0, "audio/mpeg", 0 },
+{ "ms", 0, "application/x-troff-ms", 0 },
+{ "msh", 0, "model/mesh", 0 },
+{ "mv", 0, "video/x-sgi-movie", 0 },
+{ "mxu", 0, "video/vnd.mpegurl", 0 },
+{ "nc", 0, "application/x-netcdf", 0 },
+{ "o", 0, "application/octet-stream", 0 },
+{ "oda", 0, "application/oda", 0 },
+{ "ogg", 0, "application/ogg", 0 },
+{ "pac", 0, "application/x-ns-proxy-autoconfig", 0 },
+{ "pbm", 0, "image/x-portable-bitmap", 0 },
+{ "pdb", 0, "chemical/x-pdb", 0 },
+{ "pdf", 0, "application/pdf", 0 },
+{ "pgm", 0, "image/x-portable-graymap", 0 },
+{ "pgn", 0, "application/x-chess-pgn", 0 },
+{ "png", 0, "image/png", 0 },
+{ "pnm", 0, "image/x-portable-anymap", 0 },
+{ "ppm", 0, "image/x-portable-pixmap", 0 },
+{ "ppt", 0, "application/vnd.ms-powerpoint", 0 },
+{ "ps", 0, "application/postscript", 0 },
+{ "qt", 0, "video/quicktime", 0 },
+{ "ra", 0, "audio/x-realaudio", 0 },
+{ "ram", 0, "audio/x-pn-realaudio", 0 },
+{ "ras", 0, "image/x-cmu-raster", 0 },
+{ "rdf", 0, "application/rdf+xml", 0 },
+{ "rgb", 0, "image/x-rgb", 0 },
+{ "rm", 0, "audio/x-pn-realaudio", 0 },
+{ "roff", 0, "application/x-troff", 0 },
+{ "rpm", 0, "audio/x-pn-realaudio-plugin", 0 },
+{ "rss", 0, "application/rss+xml", 0 },
+{ "rtf", 0, "text/rtf; charset=%s", 0 },
+{ "rtx", 0, "text/richtext; charset=%s", 0 },
+{ "sgm", 0, "text/sgml; charset=%s", 0 },
+{ "sgml", 0, "text/sgml; charset=%s", 0 },
+{ "sh", 0, "application/x-sh", 0 },
+{ "shar", 0, "application/x-shar", 0 },
+{ "silo", 0, "model/mesh", 0 },
+{ "sit", 0, "application/x-stuffit", 0 },
+{ "skd", 0, "application/x-koan", 0 },
+{ "skm", 0, "application/x-koan", 0 },
+{ "skp", 0, "application/x-koan", 0 },
+{ "skt", 0, "application/x-koan", 0 },
+{ "smi", 0, "application/smil", 0 },
+{ "smil", 0, "application/smil", 0 },
+{ "snd", 0, "audio/basic", 0 },
+{ "so", 0, "application/octet-stream", 0 },
+{ "spl", 0, "application/x-futuresplash", 0 },
+{ "src", 0, "application/x-wais-source", 0 },
+{ "stc", 0, "application/vnd.sun.xml.calc.template", 0 },
+{ "std", 0, "application/vnd.sun.xml.draw.template", 0 },
+{ "sti", 0, "application/vnd.sun.xml.impress.template", 0 },
+{ "stw", 0, "application/vnd.sun.xml.writer.template", 0 },
+{ "sv4cpio", 0, "application/x-sv4cpio", 0 },
+{ "sv4crc", 0, "application/x-sv4crc", 0 },
+{ "svg", 0, "image/svg+xml", 0 },
+{ "svgz", 0, "image/svg+xml", 0 },
+{ "swf", 0, "application/x-shockwave-flash", 0 },
+{ "sxc", 0, "application/vnd.sun.xml.calc", 0 },
+{ "sxd", 0, "application/vnd.sun.xml.draw", 0 },
+{ "sxg", 0, "application/vnd.sun.xml.writer.global", 0 },
+{ "sxi", 0, "application/vnd.sun.xml.impress", 0 },
+{ "sxm", 0, "application/vnd.sun.xml.math", 0 },
+{ "sxw", 0, "application/vnd.sun.xml.writer", 0 },
+{ "t", 0, "application/x-troff", 0 },
+{ "tar", 0, "application/x-tar", 0 },
+{ "tcl", 0, "application/x-tcl", 0 },
+{ "tex", 0, "application/x-tex", 0 },
+{ "texi", 0, "application/x-texinfo", 0 },
+{ "texinfo", 0, "application/x-texinfo", 0 },
+{ "tif", 0, "image/tiff", 0 },
+{ "tiff", 0, "image/tiff", 0 },
+{ "tr", 0, "application/x-troff", 0 },
+{ "tsp", 0, "application/dsptype", 0 },
+{ "tsv", 0, "text/tab-separated-values; charset=%s", 0 },
+{ "txt", 0, "text/plain; charset=%s", 0 },
+{ "ustar", 0, "application/x-ustar", 0 },
+{ "vcd", 0, "application/x-cdlink", 0 },
+{ "vrml", 0, "model/vrml", 0 },
+{ "vx", 0, "video/x-rad-screenplay", 0 },
+{ "wav", 0, "audio/x-wav", 0 },
+{ "wax", 0, "audio/x-ms-wax", 0 },
+{ "wbmp", 0, "image/vnd.wap.wbmp", 0 },
+{ "wbxml", 0, "application/vnd.wap.wbxml", 0 },
+{ "wm", 0, "video/x-ms-wm", 0 },
+{ "wma", 0, "audio/x-ms-wma", 0 },
+{ "wmd", 0, "application/x-ms-wmd", 0 },
+{ "wml", 0, "text/vnd.wap.wml", 0 },
+{ "wmlc", 0, "application/vnd.wap.wmlc", 0 },
+{ "wmls", 0, "text/vnd.wap.wmlscript", 0 },
+{ "wmlsc", 0, "application/vnd.wap.wmlscriptc", 0 },
+{ "wmv", 0, "video/x-ms-wmv", 0 },
+{ "wmx", 0, "video/x-ms-wmx", 0 },
+{ "wmz", 0, "application/x-ms-wmz", 0 },
+{ "wrl", 0, "model/vrml", 0 },
+{ "wsrc", 0, "application/x-wais-source", 0 },
+{ "wvx", 0, "video/x-ms-wvx", 0 },
+{ "xbm", 0, "image/x-xbitmap", 0 },
+{ "xht", 0, "application/xhtml+xml; charset=%s", 0 },
+{ "xhtml", 0, "application/xhtml+xml; charset=%s", 0 },
+{ "xls", 0, "application/vnd.ms-excel", 0 },
+{ "xml", 0, "text/xml; charset=%s", 0 },
+{ "xpm", 0, "image/x-xpixmap", 0 },
+{ "xsl", 0, "text/xml; charset=%s", 0 },
+{ "xwd", 0, "image/x-xwindowdump", 0 },
+{ "xyz", 0, "chemical/x-xyz", 0 },
+{ "zip", 0, "application/zip", 0 },
diff --git a/mime_types.txt b/mime_types.txt
new file mode 100644 (file)
index 0000000..d4725d9
--- /dev/null
@@ -0,0 +1,198 @@
+# mime_types.txt
+#
+# A list of file extensions followed by the corresponding MIME type.
+# Extensions not found in the table are returned as text/plain.
+
+a      application/octet-stream
+aab    application/x-authorware-bin
+aam    application/x-authorware-map
+aas    application/x-authorware-seg
+ai     application/postscript
+aif    audio/x-aiff
+aifc   audio/x-aiff
+aiff   audio/x-aiff
+asc    text/plain; charset=%s
+asf    video/x-ms-asf
+asx    video/x-ms-asf
+au     audio/basic
+avi    video/x-msvideo
+bcpio  application/x-bcpio
+bin    application/octet-stream
+bmp    image/bmp
+cdf    application/x-netcdf
+class  application/x-java-vm
+cpio   application/x-cpio
+cpt    application/mac-compactpro
+crl    application/x-pkcs7-crl
+crt    application/x-x509-ca-cert
+csh    application/x-csh
+css    text/css; charset=%s
+dcr    application/x-director
+dir    application/x-director
+djv    image/vnd.djvu
+djvu   image/vnd.djvu
+dll    application/octet-stream
+dms    application/octet-stream
+doc    application/msword
+dtd    text/xml; charset=%s
+dump   application/octet-stream
+dvi    application/x-dvi
+dxr    application/x-director
+eps    application/postscript
+etx    text/x-setext
+exe    application/octet-stream
+ez     application/andrew-inset
+fgd    application/x-director
+fh     image/x-freehand
+fh4    image/x-freehand
+fh5    image/x-freehand
+fh7    image/x-freehand
+fhc    image/x-freehand
+gif    image/gif
+gtar   application/x-gtar
+hdf    application/x-hdf
+hqx    application/mac-binhex40
+htm    text/html; charset=%s
+html   text/html; charset=%s
+ice    x-conference/x-cooltalk
+ief    image/ief
+iges   model/iges
+igs    model/iges
+iv     application/x-inventor
+jar    application/x-java-archive
+jfif   image/jpeg
+jpe    image/jpeg
+jpeg   image/jpeg
+jpg    image/jpeg
+js     application/x-javascript
+kar    audio/midi
+kml    application/vnd.google-earth.kml+xml
+kmz    application/vnd.google-earth.kmz
+latex  application/x-latex
+lha    application/octet-stream
+loc    application/xml-loc
+lzh    application/octet-stream
+m3u    audio/x-mpegurl
+man    application/x-troff-man
+mathml application/mathml+xml
+me     application/x-troff-me
+mesh   model/mesh
+mid    audio/midi
+midi   audio/midi
+mif    application/vnd.mif
+mime   message/rfc822
+mml    application/mathml+xml
+mov    video/quicktime
+movie  video/x-sgi-movie
+mp2    audio/mpeg
+mp3    audio/mpeg
+mp4    video/mp4
+mpe    video/mpeg
+mpeg   video/mpeg
+mpg    video/mpeg
+mpga   audio/mpeg
+ms     application/x-troff-ms
+msh    model/mesh
+mv     video/x-sgi-movie
+mxu    video/vnd.mpegurl
+nc     application/x-netcdf
+o      application/octet-stream
+oda    application/oda
+ogg    application/ogg
+pac    application/x-ns-proxy-autoconfig
+pbm    image/x-portable-bitmap
+pdb    chemical/x-pdb
+pdf    application/pdf
+pgm    image/x-portable-graymap
+pgn    application/x-chess-pgn
+png    image/png
+pnm    image/x-portable-anymap
+ppm    image/x-portable-pixmap
+ppt    application/vnd.ms-powerpoint
+ps     application/postscript
+qt     video/quicktime
+ra     audio/x-realaudio
+ram    audio/x-pn-realaudio
+ras    image/x-cmu-raster
+rdf    application/rdf+xml
+rgb    image/x-rgb
+rm     audio/x-pn-realaudio
+roff   application/x-troff
+rpm    audio/x-pn-realaudio-plugin
+rss    application/rss+xml
+rtf    text/rtf; charset=%s
+rtx    text/richtext; charset=%s
+sgm    text/sgml; charset=%s
+sgml   text/sgml; charset=%s
+sh     application/x-sh
+shar   application/x-shar
+silo   model/mesh
+sit    application/x-stuffit
+skd    application/x-koan
+skm    application/x-koan
+skp    application/x-koan
+skt    application/x-koan
+smi    application/smil
+smil   application/smil
+snd    audio/basic
+so     application/octet-stream
+spl    application/x-futuresplash
+src    application/x-wais-source
+stc    application/vnd.sun.xml.calc.template
+std    application/vnd.sun.xml.draw.template
+sti    application/vnd.sun.xml.impress.template
+stw    application/vnd.sun.xml.writer.template
+sv4cpio        application/x-sv4cpio
+sv4crc application/x-sv4crc
+svg    image/svg+xml
+svgz   image/svg+xml
+swf    application/x-shockwave-flash
+sxc    application/vnd.sun.xml.calc
+sxd    application/vnd.sun.xml.draw
+sxg    application/vnd.sun.xml.writer.global
+sxi    application/vnd.sun.xml.impress
+sxm    application/vnd.sun.xml.math
+sxw    application/vnd.sun.xml.writer
+t      application/x-troff
+tar    application/x-tar
+tcl    application/x-tcl
+tex    application/x-tex
+texi   application/x-texinfo
+texinfo        application/x-texinfo
+tif    image/tiff
+tiff   image/tiff
+tr     application/x-troff
+tsp    application/dsptype
+tsv    text/tab-separated-values; charset=%s
+txt    text/plain; charset=%s
+ustar  application/x-ustar
+vcd    application/x-cdlink
+vrml   model/vrml
+vx     video/x-rad-screenplay
+wav    audio/x-wav
+wax    audio/x-ms-wax
+wbmp   image/vnd.wap.wbmp
+wbxml  application/vnd.wap.wbxml
+wm     video/x-ms-wm
+wma    audio/x-ms-wma
+wmd    application/x-ms-wmd
+wml    text/vnd.wap.wml
+wmlc   application/vnd.wap.wmlc
+wmls   text/vnd.wap.wmlscript
+wmlsc  application/vnd.wap.wmlscriptc
+wmv    video/x-ms-wmv
+wmx    video/x-ms-wmx
+wmz    application/x-ms-wmz
+wrl    model/vrml
+wsrc   application/x-wais-source
+wvx    video/x-ms-wvx
+xbm    image/x-xbitmap
+xht    application/xhtml+xml; charset=%s
+xhtml  application/xhtml+xml; charset=%s
+xls    application/vnd.ms-excel
+xml    text/xml; charset=%s
+xpm    image/x-xpixmap
+xsl    text/xml; charset=%s
+xwd    image/x-xwindowdump
+xyz    chemical/x-xyz
+zip    application/zip
diff --git a/mmc.c b/mmc.c
new file mode 100644 (file)
index 0000000..93d3baa
--- /dev/null
+++ b/mmc.c
@@ -0,0 +1,531 @@
+/* mmc.c - mmap cache
+**
+** Copyright © 1998,2001,2014 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif /* HAVE_MMAP */
+
+#include "mmc.h"
+#include "libhttpd.h"
+
+#ifndef HAVE_INT64T
+typedef long long int64_t;
+#endif
+
+
+/* Defines. */
+#ifndef DEFAULT_EXPIRE_AGE
+#define DEFAULT_EXPIRE_AGE 600
+#endif
+#ifndef DESIRED_FREE_COUNT
+#define DESIRED_FREE_COUNT 100
+#endif
+#ifndef DESIRED_MAX_MAPPED_FILES
+#define DESIRED_MAX_MAPPED_FILES 2000
+#endif
+#ifndef DESIRED_MAX_MAPPED_BYTES
+#define DESIRED_MAX_MAPPED_BYTES 1000000000
+#endif
+#ifndef INITIAL_HASH_SIZE
+#define INITIAL_HASH_SIZE (1 << 10)
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+
+/* The Map struct. */
+typedef struct MapStruct {
+    ino_t ino;
+    dev_t dev;
+    off_t size;
+    time_t ct;
+    int refcount;
+    time_t reftime;
+    void* addr;
+    unsigned int hash;
+    int hash_idx;
+    struct MapStruct* next;
+    } Map;
+
+
+/* Globals. */
+static Map* maps = (Map*) 0;
+static Map* free_maps = (Map*) 0;
+static int alloc_count = 0, map_count = 0, free_count = 0;
+static Map** hash_table = (Map**) 0;
+static int hash_size;
+static unsigned int hash_mask;
+static time_t expire_age = DEFAULT_EXPIRE_AGE;
+static off_t mapped_bytes = 0;
+
+
+
+/* Forwards. */
+static void panic( void );
+static void really_unmap( Map** mm );
+static int check_hash_size( void );
+static int add_hash( Map* m );
+static Map* find_hash( ino_t ino, dev_t dev, off_t size, time_t ct );
+static unsigned int hash( ino_t ino, dev_t dev, off_t size, time_t ct );
+
+
+void*
+mmc_map( char* filename, struct stat* sbP, struct timeval* nowP )
+    {
+    time_t now;
+    struct stat sb;
+    Map* m;
+    int fd;
+
+    /* Stat the file, if necessary. */
+    if ( sbP != (struct stat*) 0 )
+       sb = *sbP;
+    else
+       {
+       if ( stat( filename, &sb ) != 0 )
+           {
+           syslog( LOG_ERR, "stat - %m" );
+           return (void*) 0;
+           }
+       }
+
+    /* Get the current time, if necessary. */
+    if ( nowP != (struct timeval*) 0 )
+       now = nowP->tv_sec;
+    else
+       now = time( (time_t*) 0 );
+
+    /* See if we have it mapped already, via the hash table. */
+    if ( check_hash_size() < 0 )
+       {
+       syslog( LOG_ERR, "check_hash_size() failure" );
+       return (void*) 0;
+       }
+    m = find_hash( sb.st_ino, sb.st_dev, sb.st_size, sb.st_ctime );
+    if ( m != (Map*) 0 )
+       {
+       /* Yep.  Just return the existing map */
+       ++m->refcount;
+       m->reftime = now;
+       return m->addr;
+       }
+
+    /* Open the file. */
+    fd = open( filename, O_RDONLY );
+    if ( fd < 0 )
+       {
+       syslog( LOG_ERR, "open - %m" );
+       return (void*) 0;
+       }
+
+    /* Find a free Map entry or make a new one. */
+    if ( free_maps != (Map*) 0 )
+       {
+       m = free_maps;
+       free_maps = m->next;
+       --free_count;
+       }
+    else
+       {
+       m = (Map*) malloc( sizeof(Map) );
+       if ( m == (Map*) 0 )
+           {
+           (void) close( fd );
+           syslog( LOG_ERR, "out of memory allocating a Map" );
+           return (void*) 0;
+           }
+       ++alloc_count;
+       }
+
+    /* Fill in the Map entry. */
+    m->ino = sb.st_ino;
+    m->dev = sb.st_dev;
+    m->size = sb.st_size;
+    m->ct = sb.st_ctime;
+    m->refcount = 1;
+    m->reftime = now;
+
+    /* Avoid doing anything for zero-length files; some systems don't like
+    ** to mmap them, other systems dislike mallocing zero bytes.
+    */
+    if ( m->size == 0 )
+       m->addr = (void*) 1;    /* arbitrary non-NULL address */
+    else
+       {
+       size_t size_size = (size_t) m->size;    /* loses on files >2GB */
+#ifdef HAVE_MMAP
+       /* Map the file into memory. */
+       m->addr = mmap( 0, size_size, PROT_READ, MAP_PRIVATE, fd, 0 );
+       if ( m->addr == (void*) -1 && errno == ENOMEM )
+           {
+           /* Ooo, out of address space.  Free all unreferenced maps
+           ** and try again.
+           */
+           panic();
+           m->addr = mmap( 0, size_size, PROT_READ, MAP_PRIVATE, fd, 0 );
+           }
+       if ( m->addr == (void*) -1 )
+           {
+           syslog( LOG_ERR, "mmap - %m" );
+           (void) close( fd );
+           free( (void*) m );
+           --alloc_count;
+           return (void*) 0;
+           }
+#else /* HAVE_MMAP */
+       /* Read the file into memory. */
+       m->addr = (void*) malloc( size_size );
+       if ( m->addr == (void*) 0 )
+           {
+           /* Ooo, out of memory.  Free all unreferenced maps
+           ** and try again.
+           */
+           panic();
+           m->addr = (void*) malloc( size_size );
+           }
+       if ( m->addr == (void*) 0 )
+           {
+           syslog( LOG_ERR, "out of memory storing a file" );
+           (void) close( fd );
+           free( (void*) m );
+           --alloc_count;
+           return (void*) 0;
+           }
+       if ( httpd_read_fully( fd, m->addr, size_size ) != size_size )
+           {
+           syslog( LOG_ERR, "read - %m" );
+           (void) close( fd );
+           free( (void*) m );
+           --alloc_count;
+           return (void*) 0;
+           }
+#endif /* HAVE_MMAP */
+       }
+    (void) close( fd );
+
+    /* Put the Map into the hash table. */
+    if ( add_hash( m ) < 0 )
+       {
+       syslog( LOG_ERR, "add_hash() failure" );
+       free( (void*) m );
+       --alloc_count;
+       return (void*) 0;
+       }
+
+    /* Put the Map on the active list. */
+    m->next = maps;
+    maps = m;
+    ++map_count;
+
+    /* Update the total byte count. */
+    mapped_bytes += m->size;
+
+    /* And return the address. */
+    return m->addr;
+    }
+
+
+void
+mmc_unmap( void* addr, struct stat* sbP, struct timeval* nowP )
+    {
+    Map* m = (Map*) 0;
+
+    /* Find the Map entry for this address.  First try a hash. */
+    if ( sbP != (struct stat*) 0 )
+       {
+       m = find_hash( sbP->st_ino, sbP->st_dev, sbP->st_size, sbP->st_ctime );
+       if ( m != (Map*) 0 && m->addr != addr )
+           m = (Map*) 0;
+       }
+    /* If that didn't work, try a full search. */
+    if ( m == (Map*) 0 )
+       for ( m = maps; m != (Map*) 0; m = m->next )
+           if ( m->addr == addr )
+               break;
+    if ( m == (Map*) 0 )
+       syslog( LOG_ERR, "mmc_unmap failed to find entry!" );
+    else if ( m->refcount <= 0 )
+       syslog( LOG_ERR, "mmc_unmap found zero or negative refcount!" );
+    else
+       {
+       --m->refcount;
+       if ( nowP != (struct timeval*) 0 )
+           m->reftime = nowP->tv_sec;
+       else
+           m->reftime = time( (time_t*) 0 );
+       }
+    }
+
+
+void
+mmc_cleanup( struct timeval* nowP )
+    {
+    time_t now;
+    Map** mm;
+    Map* m;
+
+    /* Get the current time, if necessary. */
+    if ( nowP != (struct timeval*) 0 )
+       now = nowP->tv_sec;
+    else
+       now = time( (time_t*) 0 );
+
+    /* Really unmap any unreferenced entries older than the age limit. */
+    for ( mm = &maps; *mm != (Map*) 0; )
+       {
+       m = *mm;
+       if ( m->refcount == 0 && now - m->reftime >= expire_age )
+           really_unmap( mm );
+       else
+           mm = &(*mm)->next;
+       }
+
+    /* Adjust the age limit if there are too many bytes mapped, or
+    ** too many or too few files mapped.
+    */
+    if ( mapped_bytes > DESIRED_MAX_MAPPED_BYTES )
+       expire_age = MAX( ( expire_age * 2 ) / 3, DEFAULT_EXPIRE_AGE / 10 );
+    else if ( map_count > DESIRED_MAX_MAPPED_FILES )
+       expire_age = MAX( ( expire_age * 2 ) / 3, DEFAULT_EXPIRE_AGE / 10 );
+    else if ( map_count < DESIRED_MAX_MAPPED_FILES / 2 )
+       expire_age = MIN( ( expire_age * 5 ) / 4, DEFAULT_EXPIRE_AGE * 3 );
+
+    /* Really free excess blocks on the free list. */
+    while ( free_count > DESIRED_FREE_COUNT )
+       {
+       m = free_maps;
+       free_maps = m->next;
+       --free_count;
+       free( (void*) m );
+       --alloc_count;
+       }
+    }
+
+
+static void
+panic( void )
+    {
+    Map** mm;
+    Map* m;
+
+    syslog( LOG_ERR, "mmc panic - freeing all unreferenced maps" );
+
+    /* Really unmap all unreferenced entries. */
+    for ( mm = &maps; *mm != (Map*) 0; )
+       {
+       m = *mm;
+       if ( m->refcount == 0 )
+           really_unmap( mm );
+       else
+           mm = &(*mm)->next;
+       }
+    }
+
+
+static void
+really_unmap( Map** mm )
+    {
+    Map* m;
+
+    m = *mm;
+    if ( m->size != 0 )
+       {
+#ifdef HAVE_MMAP
+       if ( munmap( m->addr, m->size ) < 0 )
+           syslog( LOG_ERR, "munmap - %m" );
+#else /* HAVE_MMAP */
+       free( (void*) m->addr );
+#endif /* HAVE_MMAP */
+       }
+    /* Update the total byte count. */
+    mapped_bytes -= m->size;
+    /* And move the Map to the free list. */
+    *mm = m->next;
+    --map_count;
+    m->next = free_maps;
+    free_maps = m;
+    ++free_count;
+    /* This will sometimes break hash chains, but that's harmless; the
+    ** unmapping code that searches the hash table knows to keep searching.
+    */
+    hash_table[m->hash_idx] = (Map*) 0;
+    }
+
+
+void
+mmc_term( void )
+    {
+    Map* m;
+
+    while ( maps != (Map*) 0 )
+       really_unmap( &maps );
+    while ( free_maps != (Map*) 0 )
+       {
+       m = free_maps;
+       free_maps = m->next;
+       --free_count;
+       free( (void*) m );
+       --alloc_count;
+       }
+    }
+
+
+/* Make sure the hash table is big enough. */
+static int
+check_hash_size( void )
+    {
+    int i;
+    Map* m;
+
+    /* Are we just starting out? */
+    if ( hash_table == (Map**) 0 )
+       {
+       hash_size = INITIAL_HASH_SIZE;
+       hash_mask = hash_size - 1;
+       }
+    /* Is it at least three times bigger than the number of entries? */
+    else if ( hash_size >= map_count * 3 )
+       return 0;
+    else
+       {
+       /* No, got to expand. */
+       free( (void*) hash_table );
+       /* Double the hash size until it's big enough. */
+       do
+           {
+           hash_size = hash_size << 1;
+           }
+       while ( hash_size < map_count * 6 );
+       hash_mask = hash_size - 1;
+       }
+    /* Make the new table. */
+    hash_table = (Map**) malloc( hash_size * sizeof(Map*) );
+    if ( hash_table == (Map**) 0 )
+       return -1;
+    /* Clear it. */
+    for ( i = 0; i < hash_size; ++i )
+       hash_table[i] = (Map*) 0;
+    /* And rehash all entries. */
+    for ( m = maps; m != (Map*) 0; m = m->next )
+       if ( add_hash( m ) < 0 )
+           return -1;
+    return 0;
+    }
+
+
+static int
+add_hash( Map* m )
+    {
+    unsigned int h, he, i;
+
+    h = hash( m->ino, m->dev, m->size, m->ct );
+    he = ( h + hash_size - 1 ) & hash_mask;
+    for ( i = h; ; i = ( i + 1 ) & hash_mask )
+       {
+       if ( hash_table[i] == (Map*) 0 )
+           {
+           hash_table[i] = m;
+           m->hash = h;
+           m->hash_idx = i;
+           return 0;
+           }
+       if ( i == he )
+           break;
+       }
+    return -1;
+    }
+
+
+static Map*
+find_hash( ino_t ino, dev_t dev, off_t size, time_t ct )
+    {
+    unsigned int h, he, i;
+    Map* m;
+
+    h = hash( ino, dev, size, ct );
+    he = ( h + hash_size - 1 ) & hash_mask;
+    for ( i = h; ; i = ( i + 1 ) & hash_mask )
+       {
+       m = hash_table[i];
+       if ( m == (Map*) 0 )
+           break;
+       if ( m->hash == h && m->ino == ino && m->dev == dev &&
+            m->size == size && m->ct == ct )
+           return m;
+       if ( i == he )
+           break;
+       }
+    return (Map*) 0;
+    }
+
+
+static unsigned int
+hash( ino_t ino, dev_t dev, off_t size, time_t ct )
+    {
+    unsigned int h = 177573;
+
+    h ^= ino;
+    h += h << 5;
+    h ^= dev;
+    h += h << 5;
+    h ^= size;
+    h += h << 5;
+    h ^= ct;
+
+    return h & hash_mask;
+    }
+
+
+/* Generate debugging statistics syslog message. */
+void
+mmc_logstats( long secs )
+    {
+    syslog(
+       LOG_NOTICE, "  map cache - %d allocated, %d active (%lld bytes), %d free; hash size: %d; expire age: %lld",
+       alloc_count, map_count, (long long) mapped_bytes, free_count, hash_size,
+       (long long) expire_age );
+    if ( map_count + free_count != alloc_count )
+       syslog( LOG_ERR, "map counts don't add up!" );
+    }
diff --git a/mmc.h b/mmc.h
new file mode 100644 (file)
index 0000000..7ca0448
--- /dev/null
+++ b/mmc.h
@@ -0,0 +1,55 @@
+/* mmc.h - header file for mmap cache package
+**
+** Copyright © 1998,2014 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _MMC_H_
+#define _MMC_H_
+
+/* Returns an mmap()ed area for the given file, or (void*) 0 on errors.
+** If you have a stat buffer on the file, pass it in, otherwise pass 0.
+** Same for the current time.
+*/
+void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP );
+
+/* Done with an mmap()ed area that was returned by mmc_map().
+** If you have a stat buffer on the file, pass it in, otherwise pass 0.
+** Same for the current time.
+*/
+void mmc_unmap( void* addr, struct stat* sbP, struct timeval* nowP );
+
+/* Clean up the mmc package, freeing any unused storage.
+** This should be called periodically, say every five minutes.
+** If you have the current time, pass it in, otherwise pass 0.
+*/
+void mmc_cleanup( struct timeval* nowP );
+
+/* Free all storage, usually in preparation for exitting. */
+void mmc_term( void );
+
+/* Generate debugging statistics syslog message. */
+void mmc_logstats( long secs );
+
+#endif /* _MMC_H_ */
diff --git a/mmc.o b/mmc.o
new file mode 100644 (file)
index 0000000..3343f88
Binary files /dev/null and b/mmc.o differ
diff --git a/scripts/500.thttpd-rotate b/scripts/500.thttpd-rotate
new file mode 100755 (executable)
index 0000000..a172b83
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# thttpd-rotate - nightly script to rotate thttpd's log files on FreeBSD
+#
+# This goes in /etc/periodic/daily.  It rotates the log files and then
+# tells thttpd to re-open its log file.
+
+cd /usr/local/www/chroot/logs
+rm -f thttpd_log.7.gz
+mv thttpd_log.6.gz thttpd_log.7.gz
+mv thttpd_log.5.gz thttpd_log.6.gz
+mv thttpd_log.4.gz thttpd_log.5.gz
+mv thttpd_log.3.gz thttpd_log.4.gz
+mv thttpd_log.2.gz thttpd_log.3.gz
+mv thttpd_log.1.gz thttpd_log.2.gz
+mv thttpd_log thttpd_log.1
+kill -HUP `cat /var/run/thttpd.pid`
+sleep 1
+gzip -f thttpd_log.1
diff --git a/scripts/thttpd.sh b/scripts/thttpd.sh
new file mode 100755 (executable)
index 0000000..22564ba
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# thttpd.sh - startup script for thttpd on FreeBSD
+#
+# This should be manually installed as:
+#   /usr/local/etc/rc.d/thttpd
+# It gets run at boot-time.
+#
+# Variables available:
+#   thttpd_enable='YES'
+#   thttpd_program='/usr/local/sbin/thttpd'
+#   thttpd_pidfile='/var/run/thttpd.pid'
+#   thttpd_devfs=...
+#   thttpd_flags=...
+#
+# PROVIDE: thttpd
+# REQUIRE: LOGIN FILESYSTEMS
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name='thttpd'
+rcvar='thttpd_enable'
+start_precmd='thttpd_precmd'
+stop_cmd='thttpd_stop'
+thttpd_enable_defval='NO'
+
+load_rc_config "$name"
+command="${thttpd_program:-/usr/local/sbin/${name}}"
+pidfile="${thttpd_pidfile:-/var/run/${name}.pid}"
+command_args="-i ${pidfile}"
+
+thttpd_precmd ()
+{
+       if [ -n "$thttpd_devfs" ] ; then
+               mount -t devfs devfs "$thttpd_devfs"
+               devfs -m "$thttpd_devfs" rule -s 1 applyset
+               devfs -m "$thttpd_devfs" rule -s 2 applyset
+       fi
+}
+
+thttpd_stop ()
+{
+       kill -USR1 `cat "$pidfile"`
+}
+
+run_rc_command "$1"
diff --git a/scripts/thttpd_wrapper b/scripts/thttpd_wrapper
new file mode 100755 (executable)
index 0000000..631c34d
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# thttpd_wrapper - wrapper script for thttpd on FreeBSD
+#
+# This goes in /usr/local/sbin.  It backgrounds itself, and then runs
+# thttpd in a loop.  If thttpd exits then the script restarts it automatically.
+#
+# The -D flag tells thttpd to *not* put itself into the background,
+# and the -C flag tells it to get the rest of its configuration from
+# the specified config file.
+
+(
+    while true ; do
+       /usr/local/sbin/thttpd -D -C /usr/local/www/thttpd_config
+       if [ -f /var/run/nologin ] ; then
+           exit
+       fi
+       sleep 10
+       egrep ' thttpd[:\[]' /var/log/messages |
+         tail -33 |
+         mail -s "thttpd on `hostname` restarted" root
+    done
+) &
diff --git a/strerror.c b/strerror.c
new file mode 100644 (file)
index 0000000..6a161e6
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strerror.c  5.1 (Berkeley) 4/9/89";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+char *
+strerror(errnum)
+       int errnum;
+{
+       extern int sys_nerr;
+       extern char *sys_errlist[];
+       static char ebuf[20];
+
+       if ((unsigned int)errnum < sys_nerr)
+               return(sys_errlist[errnum]);
+       (void)sprintf(ebuf, "Unknown error: %d", errnum);
+       return(ebuf);
+}
diff --git a/tdate_parse.c b/tdate_parse.c
new file mode 100644 (file)
index 0000000..a7ea7fa
--- /dev/null
@@ -0,0 +1,328 @@
+/* tdate_parse - parse string dates into internal form, stripped-down version
+**
+** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+/* This is a stripped-down version of date_parse.c, available at
+** http://www.acme.com/software/date_parse/
+*/
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "tdate_parse.h"
+
+
+struct strlong {
+    char* s;
+    long l;
+    };
+
+
+static void
+pound_case( char* str )
+    {
+    for ( ; *str != '\0'; ++str )
+       {
+       if ( isupper( (int) *str ) )
+           *str = tolower( (int) *str );
+       }
+    }
+
+
+static int
+strlong_compare( const void* v1, const void* v2 )
+    {
+    const struct strlong* s1 = (const struct strlong*) v1;
+    const struct strlong* s2 = (const struct strlong*) v2;
+    return strcmp( s1->s, s2->s );
+    }
+
+
+static int
+strlong_search( char* str, struct strlong* tab, int n, long* lP )
+    {
+    int i, h, l, r;
+
+    l = 0;
+    h = n - 1;
+    for (;;)
+       {
+       i = ( h + l ) / 2;
+       r = strcmp( str, tab[i].s );
+       if ( r < 0 )
+           h = i - 1;
+       else if ( r > 0 )
+           l = i + 1;
+       else
+           {
+           *lP = tab[i].l;
+           return 1;
+           }
+       if ( h < l )
+           return 0;
+       }
+    }
+
+
+static int
+scan_wday( char* str_wday, long* tm_wdayP )
+    {
+    static struct strlong wday_tab[] = {
+       { "sun", 0 }, { "sunday", 0 },
+       { "mon", 1 }, { "monday", 1 },
+       { "tue", 2 }, { "tuesday", 2 },
+       { "wed", 3 }, { "wednesday", 3 },
+       { "thu", 4 }, { "thursday", 4 },
+       { "fri", 5 }, { "friday", 5 },
+       { "sat", 6 }, { "saturday", 6 },
+       };
+    static int sorted = 0;
+
+    if ( ! sorted )
+       {
+       (void) qsort(
+           wday_tab, sizeof(wday_tab)/sizeof(struct strlong),
+           sizeof(struct strlong), strlong_compare );
+       sorted = 1;
+       }
+    pound_case( str_wday );
+    return strlong_search(
+       str_wday, wday_tab, sizeof(wday_tab)/sizeof(struct strlong), tm_wdayP );
+    }
+
+
+static int
+scan_mon( char* str_mon, long* tm_monP )
+    {
+    static struct strlong mon_tab[] = {
+       { "jan", 0 }, { "january", 0 },
+       { "feb", 1 }, { "february", 1 },
+       { "mar", 2 }, { "march", 2 },
+       { "apr", 3 }, { "april", 3 },
+       { "may", 4 },
+       { "jun", 5 }, { "june", 5 },
+       { "jul", 6 }, { "july", 6 },
+       { "aug", 7 }, { "august", 7 },
+       { "sep", 8 }, { "september", 8 },
+       { "oct", 9 }, { "october", 9 },
+       { "nov", 10 }, { "november", 10 },
+       { "dec", 11 }, { "december", 11 },
+       };
+    static int sorted = 0;
+
+    if ( ! sorted )
+       {
+       (void) qsort(
+           mon_tab, sizeof(mon_tab)/sizeof(struct strlong),
+           sizeof(struct strlong), strlong_compare );
+       sorted = 1;
+       }
+    pound_case( str_mon );
+    return strlong_search(
+       str_mon, mon_tab, sizeof(mon_tab)/sizeof(struct strlong), tm_monP );
+    }
+
+
+static int
+is_leap( int year )
+    {
+    return year % 400? ( year % 100 ? ( year % 4 ? 0 : 1 ) : 0 ) : 1;
+    }
+
+
+/* Basically the same as mktime(). */
+static time_t
+tm_to_time( struct tm* tmP )
+    {
+    time_t t;
+    static int monthtab[12] = {
+       0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+    /* Years since epoch, converted to days. */
+    t = ( tmP->tm_year - 70 ) * 365;
+    /* Leap days for previous years - this will break in 2100! */
+    t += ( tmP->tm_year - 69 ) / 4;
+    /* Days for the beginning of this month. */
+    t += monthtab[tmP->tm_mon];
+    /* Leap day for this year. */
+    if ( tmP->tm_mon >= 2 && is_leap( tmP->tm_year + 1900 ) )
+       ++t;
+    /* Days since the beginning of this month. */
+    t += tmP->tm_mday - 1;     /* 1-based field */
+    /* Hours, minutes, and seconds. */
+    t = t * 24 + tmP->tm_hour;
+    t = t * 60 + tmP->tm_min;
+    t = t * 60 + tmP->tm_sec;
+
+    return t;
+    }
+
+
+time_t
+tdate_parse( char* str )
+    {
+    struct tm tm;
+    char* cp;
+    char str_mon[500], str_wday[500];
+    int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
+    long tm_mon, tm_wday;
+    time_t t;
+
+    /* Initialize. */
+    (void) memset( (char*) &tm, 0, sizeof(struct tm) );
+
+    /* Skip initial whitespace ourselves - sscanf is clumsy at this. */
+    for ( cp = str; *cp == ' ' || *cp == '\t'; ++cp )
+       continue;
+
+    /* And do the sscanfs.  WARNING: you can add more formats here,
+    ** but be careful!  You can easily screw up the parsing of existing
+    ** formats when you add new ones.  The order is important.
+    */
+
+    /* DD-mth-YY HH:MM:SS GMT */
+    if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
+               &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
+               &tm_sec ) == 6 &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_mday = tm_mday;
+       tm.tm_mon = tm_mon;
+       tm.tm_year = tm_year;
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       }
+
+    /* DD mth YY HH:MM:SS GMT */
+    else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
+               &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
+               &tm_sec) == 6 &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_mday = tm_mday;
+       tm.tm_mon = tm_mon;
+       tm.tm_year = tm_year;
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       }
+
+    /* HH:MM:SS GMT DD-mth-YY */
+    else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
+               &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
+               &tm_year ) == 6 &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       tm.tm_mday = tm_mday;
+       tm.tm_mon = tm_mon;
+       tm.tm_year = tm_year;
+       }
+
+    /* HH:MM:SS GMT DD mth YY */
+    else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
+               &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
+               &tm_year ) == 6 &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       tm.tm_mday = tm_mday;
+       tm.tm_mon = tm_mon;
+       tm.tm_year = tm_year;
+       }
+
+    /* wdy, DD-mth-YY HH:MM:SS GMT */
+    else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
+               str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
+               &tm_sec ) == 7 &&
+           scan_wday( str_wday, &tm_wday ) &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_wday = tm_wday;
+       tm.tm_mday = tm_mday;
+       tm.tm_mon = tm_mon;
+       tm.tm_year = tm_year;
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       }
+
+    /* wdy, DD mth YY HH:MM:SS GMT */
+    else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
+               str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
+               &tm_sec ) == 7 &&
+           scan_wday( str_wday, &tm_wday ) &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_wday = tm_wday;
+       tm.tm_mday = tm_mday;
+       tm.tm_mon = tm_mon;
+       tm.tm_year = tm_year;
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       }
+
+    /* wdy mth DD HH:MM:SS GMT YY */
+    else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
+               str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
+               &tm_year ) == 7 &&
+           scan_wday( str_wday, &tm_wday ) &&
+           scan_mon( str_mon, &tm_mon ) )
+       {
+       tm.tm_wday = tm_wday;
+       tm.tm_mon = tm_mon;
+       tm.tm_mday = tm_mday;
+       tm.tm_hour = tm_hour;
+       tm.tm_min = tm_min;
+       tm.tm_sec = tm_sec;
+       tm.tm_year = tm_year;
+       }
+    else
+       return (time_t) -1;
+
+    if ( tm.tm_year > 1900 )
+       tm.tm_year -= 1900;
+    else if ( tm.tm_year < 70 )
+       tm.tm_year += 100;
+
+    t = tm_to_time( &tm );
+
+    return t;
+    }
diff --git a/tdate_parse.h b/tdate_parse.h
new file mode 100644 (file)
index 0000000..aaf0b66
--- /dev/null
@@ -0,0 +1,33 @@
+/* tdate_parse.h - parse string dates into internal form, stripped-down version
+**
+** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _TDATE_PARSE_H_
+#define _TDATE_PARSE_H_
+
+time_t tdate_parse( char* str );
+
+#endif /* _TDATE_PARSE_H_ */
diff --git a/tdate_parse.o b/tdate_parse.o
new file mode 100644 (file)
index 0000000..67e9073
Binary files /dev/null and b/tdate_parse.o differ
diff --git a/thttpd b/thttpd
new file mode 100755 (executable)
index 0000000..ef70ff0
Binary files /dev/null and b/thttpd differ
diff --git a/thttpd.8 b/thttpd.8
new file mode 100644 (file)
index 0000000..040f74c
--- /dev/null
+++ b/thttpd.8
@@ -0,0 +1,596 @@
+.TH thttpd 8 "29 February 2000"
+.SH NAME
+thttpd - tiny/turbo/throttling HTTP server
+.SH SYNOPSIS
+.B thttpd
+.RB [ -C
+.IR configfile ]
+.RB [ -p
+.IR port ]
+.RB [ -d
+.IR dir ]
+.RB [ -dd
+.IR data_dir ]
+.RB [ -r | -nor ]
+.RB [ -s | -nos ]
+.RB [ -v | -nov ]
+.RB [ -g | -nog ]
+.RB [ -u
+.IR user ]
+.RB [ -c
+.IR cgipat ]
+.RB [ -t
+.IR throttles ]
+.RB [ -h
+.IR host ]
+.RB [ -l
+.IR logfile ]
+.RB [ -i
+.IR pidfile ]
+.RB [ -T
+.IR charset ]
+.RB [ -P
+.IR P3P ]
+.RB [ -M
+.IR maxage ]
+.RB [ -V ]
+.RB [ -D ]
+.SH DESCRIPTION
+.PP
+.I thttpd
+is a simple, small, fast, and secure HTTP server.
+It doesn't have a lot of special features, but it suffices for most uses of
+the web, it's about as fast as the best full-featured servers (Apache, NCSA,
+Netscape),
+and it has one extremely useful feature (URL-traffic-based throttling)
+that no other server currently has.
+.SH OPTIONS
+.TP
+.B -C
+Specifies a config-file to read.
+All options can be set either by command-line flags or in the config file.
+See below for details.
+.TP
+.B -p
+Specifies an alternate port number to listen on.
+The default is 80.
+The config-file option name for this flag is "port",
+and the config.h option is DEFAULT_PORT.
+.TP
+.B -d
+Specifies a directory to chdir() to at startup.
+This is merely a convenience - you could just as easily
+do a cd in the shell script that invokes the program.
+The config-file option name for this flag is "dir",
+and the config.h options are WEBDIR, USE_USER_DIR.
+.TP
+.B -r
+Do a chroot() at initialization time, restricting file access
+to the program's current directory.
+If -r is the compiled-in default, then -nor disables it.
+See below for details.
+The config-file option names for this flag are "chroot" and "nochroot",
+and the config.h option is ALWAYS_CHROOT.
+.TP
+.B -dd
+Specifies a directory to chdir() to after chrooting.
+If you're not chrooting, you might as well do a single chdir() with
+the -d flag.
+If you are chrooting, this lets you put the web files in a subdirectory
+of the chroot tree, instead of in the top level mixed in with the
+chroot files.
+The config-file option name for this flag is "data_dir".
+.TP
+.B -nos
+Don't do explicit symbolic link checking.
+Normally, thttpd explicitly expands any symbolic links in filenames,
+to check that the resulting path stays within the original document tree.
+If you want to turn off this check and save some CPU time, you can use
+the -nos flag, however this is not recommended.
+Note, though, that if you are using the chroot option, the symlink
+checking is unnecessary and is turned off, so the safe way to save
+those CPU cycles is to use chroot.
+The config-file option names for this flag are "symlinkcheck" and "nosymlinkcheck".
+.TP
+.B -v
+Do el-cheapo virtual hosting.
+If -v is the compiled-in default, then -nov disables it.
+See below for details.
+The config-file option names for this flag are "vhost" and "novhost",
+and the config.h option is ALWAYS_VHOST.
+.TP
+.B -g
+Use a global passwd file.
+This means that every file in the entire document tree is protected by
+the single .htpasswd file at the top of the tree.
+Otherwise the semantics of the .htpasswd file are the same.
+If this option is set but there is no .htpasswd file in
+the top-level directory, then thttpd proceeds as if the option was
+not set - first looking for a local .htpasswd file, and if that doesn't
+exist either then serving the file without any password.
+If -g is the compiled-in default, then -nog disables it.
+The config-file option names for this flag are "globalpasswd" and
+"noglobalpasswd",
+and the config.h option is ALWAYS_GLOBAL_PASSWD.
+.TP
+.B -u
+Specifies what user to switch to after initialization when started as root.
+The default is "nobody".
+The config-file option name for this flag is "user",
+and the config.h option is DEFAULT_USER.
+.TP
+.B -c
+Specifies a wildcard pattern for CGI programs, for instance "**.cgi"
+or "/cgi-bin/*".
+See below for details.
+The config-file option name for this flag is "cgipat",
+and the config.h option is CGI_PATTERN.
+.TP
+.B -t
+Specifies a file of throttle settings.
+See below for details.
+The config-file option name for this flag is "throttles".
+.TP
+.B -h
+Specifies a hostname to bind to, for multihoming.
+The default is to bind to all hostnames supported on the local machine.
+See below for details.
+The config-file option name for this flag is "host",
+and the config.h option is SERVER_NAME.
+.TP
+.B -l
+Specifies a file for logging.
+If no -l argument is specified, thttpd logs via syslog().
+If "-l /dev/null" is specified, thttpd doesn't log at all.
+The config-file option name for this flag is "logfile".
+.TP
+.B -i
+Specifies a file to write the process-id to.
+If no file is specified, no process-id is written.
+You can use this file to send signals to thttpd.
+See below for details.
+The config-file option name for this flag is "pidfile".
+.TP
+.B -T
+Specifies the character set to use with text MIME types.
+The default is UTF-8.
+The config-file option name for this flag is "charset",
+and the config.h option is DEFAULT_CHARSET.
+.TP
+.B -P
+Specifies a P3P server privacy header to be returned with all responses.
+See http://www.w3.org/P3P/ for details.
+Thttpd doesn't do anything at all with the string except put it in the
+P3P: response header.
+The config-file option name for this flag is "p3p".
+.TP
+.B -M
+Specifies the number of seconds to be used in a "Cache-Control: max-age"
+header to be returned with all responses.
+An equivalent "Expires" header is also generated.
+The default is no Cache-Control or Expires headers,
+which is just fine for most sites.
+The config-file option name for this flag is "max_age".
+.TP
+.B -V
+Shows the current version info.
+.TP
+.B -D
+This was originally just a debugging flag, however it's worth mentioning
+because one of the things it does is prevent thttpd from making itself
+a background daemon.
+Instead it runs in the foreground like a regular program.
+This is necessary when you want to run thttpd wrapped in a little shell
+script that restarts it if it exits.
+.SH "CONFIG-FILE"
+.PP
+All the command-line options can also be set in a config file.
+One advantage of using a config file is that the file can be changed,
+and thttpd will pick up the changes with a restart.
+.PP
+The syntax of the config file is simple, a series of "option" or
+"option=value" separated by whitespace.
+The option names are listed above with their corresponding command-line flags.
+.SH "CHROOT"
+.PP
+chroot() is a system call that restricts the program's view
+of the filesystem to the current directory and directories
+below it.
+It becomes impossible for remote users to access any file
+outside of the initial directory.
+The restriction is inherited by child processes, so CGI programs get it too.
+This is a very strong security measure, and is recommended.
+The only downside is that only root can call chroot(), so this means
+the program must be started as root.
+However, the last thing it does during initialization is to
+give up root access by becoming another user, so this is safe.
+.PP
+The program can also be compile-time configured to always
+do a chroot(), without needing the -r flag.
+.PP
+Note that with some other web servers, such as NCSA httpd, setting
+up a directory tree for use with chroot() is complicated, involving
+creating a bunch of special directories and copying in various files.
+With thttpd it's a lot easier, all you have to do is make sure
+any shells, utilities, and config files used by your CGI programs and
+scripts are available.
+If you have CGI disabled, or if you make a policy that all CGI programs
+must be written in a compiled language such as C and statically linked,
+then you probably don't have to do any setup at all.
+.PP
+However, one thing you should do is tell syslogd about the chroot tree,
+so that thttpd can still generate syslog messages.
+Check your system's syslodg man page for how to do this.
+In FreeBSD you would put something like this in /etc/rc.conf:
+.nf
+    syslogd_flags="-l /usr/local/www/data/dev/log"
+.fi
+Substitute in your own chroot tree's pathname, of course.
+Don't worry about creating the log socket, syslogd wants to do that itself.
+(You may need to create the dev directory.)
+In Linux the flag is -a instead of -l, and there may be other differences.
+.PP
+Relevant config.h option: ALWAYS_CHROOT.
+.SH "CGI"
+.PP
+thttpd supports the CGI 1.1 spec.
+.PP
+In order for a CGI program to be run, its name must match the pattern
+specified either at compile time or on the command line with the -c flag.
+This is a simple shell-style filename pattern.
+You can use * to match any string not including a slash,
+or ** to match any string including slashes,
+or ? to match any single character.
+You can also use multiple such patterns separated by |.
+The patterns get checked against the filename
+part of the incoming URL.
+Don't forget to quote any wildcard characters so that the shell doesn't
+mess with them.
+.PP
+Restricting CGI programs to a single directory lets the site administrator
+review them for security holes, and is strongly recommended.
+If there are individual users that you trust, you can enable their
+directories too.
+.PP
+If no CGI pattern is specified, neither here nor at compile time,
+then CGI programs cannot be run at all.
+If you want to disable CGI as a security measure, that's how you do it, just
+comment out the patterns in the config file and don't run with the -c flag.
+.PP
+Note: the current working directory when a CGI program gets run is
+the directory that the CGI program lives in.
+This isn't in the CGI 1.1 spec, but it's what most other HTTP servers do.
+.PP
+Relevant config.h options: CGI_PATTERN, CGI_TIMELIMIT, CGI_NICE, CGI_PATH, CGI_LD_LIBRARY_PATH, CGIBINDIR.
+.SH "BASIC AUTHENTICATION"
+.PP
+Basic Authentication is available as an option at compile time.
+If enabled, it uses a password file in the directory to be protected,
+called .htpasswd by default.
+This file is formatted as the familiar colon-separated
+username/encrypted-password pair, records delimited by newlines.
+The protection does not carry over to subdirectories.
+The utility program htpasswd(1) is included to help create and
+modify .htpasswd files.
+.PP
+Relevant config.h option: AUTH_FILE
+.SH "THROTTLING"
+.PP
+The throttle file lets you set maximum byte rates on URLs or URL groups.
+You can optionally set a minimum rate too.
+The format of the throttle file is very simple.
+A # starts a comment, and the rest of the line is ignored.
+Blank lines are ignored.
+The rest of the lines should consist of a pattern, whitespace, and a number.
+The pattern is a simple shell-style filename pattern, using ?/**/*, or
+multiple such patterns separated by |.
+.PP
+The numbers in the file are byte rates, specified in units of bytes per second.
+For comparison, a v.90 modem gives about 5000 B/s depending on compression,
+a double-B-channel ISDN line about 12800 B/s, and a T1 line is about
+150000 B/s.
+If you want to set a minimum rate as well, use number-number.
+.PP
+Example:
+.nf
+  # throttle file for www.acme.com
+
+  **              2000-100000  # limit total web usage to 2/3 of our T1,
+                               # but never go below 2000 B/s
+  **.jpg|**.gif   50000   # limit images to 1/3 of our T1
+  **.mpg          20000   # and movies to even less
+  jef/**          20000   # jef's pages are too popular
+.fi
+.PP
+Throttling is implemented by checking each incoming URL filename against all
+of the patterns in the throttle file.
+The server accumulates statistics on how much bandwidth each pattern
+has accounted for recently (via a rolling average).
+If a URL matches a pattern that has been exceeding its specified limit,
+then the data returned is actually slowed down, with
+pauses between each block.
+If that's not possible (e.g. for CGI programs) or if the bandwidth has gotten
+way larger than the limit, then the server returns a special code
+saying 'try again later'.
+.PP
+The minimum rates are implemented similarly.
+If too many people are trying to fetch something at the same time,
+throttling may slow down each connection so much that it's not really
+useable.
+Furthermore, all those slow connections clog up the server, using
+up file handles and connection slots.
+Setting a minimum rate says that past a certain point you should not
+even bother - the server returns the 'try again later" code and the
+connection isn't even started.
+.PP
+There is no provision for setting a maximum connections/second throttle,
+because throttling a request uses as much cpu as handling it, so
+there would be no point.
+There is also no provision for throttling the number of simultaneous
+connections on a per-URL basis.
+However you can control the overall number of connections for the whole
+server very simply, by setting the operating system's per-process file
+descriptor limit before starting thttpd.
+Be sure to set the hard limit, not the soft limit.
+.SH "MULTIHOMING"
+.PP
+Multihoming means using one machine to serve multiple hostnames.
+For instance, if you're an internet provider and you want to let
+all of your customers have customized web addresses, you might
+have www.joe.acme.com, www.jane.acme.com, and your own www.acme.com,
+all running on the same physical hardware.
+This feature is also known as "virtual hosts".
+There are three steps to setting this up.
+.PP
+One, make DNS entries for all of the hostnames.
+The current way to do this, allowed by HTTP/1.1, is to use CNAME aliases,
+like so:
+.nf
+  www.acme.com IN A 192.100.66.1
+  www.joe.acme.com IN CNAME www.acme.com
+  www.jane.acme.com IN CNAME www.acme.com
+.fi
+However, this is incompatible with older HTTP/1.0 browsers.
+If you want to stay compatible, there's a different way - use A records
+instead, each with a different IP address, like so:
+.nf
+  www.acme.com IN A 192.100.66.1
+  www.joe.acme.com IN A 192.100.66.200
+  www.jane.acme.com IN A 192.100.66.201
+.fi
+This is bad because it uses extra IP addresses, a somewhat scarce resource.
+But if you want people with older browsers to be able to visit your
+sites, you still have to do it this way.
+.PP
+Step two.
+If you're using the modern CNAME method of multihoming, then you can
+skip this step.
+Otherwise, using the older multiple-IP-address method you
+must set up IP aliases or multiple interfaces for the extra addresses.
+You can use ifconfig(8)'s alias command to tell the machine to answer to
+all of the different IP addresses.
+Example:
+.nf
+  ifconfig le0 www.acme.com
+  ifconfig le0 www.joe.acme.com alias
+  ifconfig le0 www.jane.acme.com alias
+.fi
+If your OS's version of ifconfig doesn't have an alias command, you're
+probably out of luck (but see http://www.acme.com/software/thttpd/notes.html).
+.PP
+Third and last, you must set up thttpd to handle the multiple hosts.
+The easiest way is with the -v flag, or the ALWAYS_VHOST config.h option.
+This works with either CNAME multihosting or multiple-IP multihosting.
+What it does is send each incoming request to a subdirectory based on the
+hostname it's intended for.
+All you have to do in order to set things up is to create those subdirectories
+in the directory where thttpd will run.
+With the example above, you'd do like so:
+.nf
+  mkdir www.acme.com www.joe.acme.com www.jane.acme.com
+.fi
+If you're using old-style multiple-IP multihosting, you should also create
+symbolic links from the numeric addresses to the names, like so:
+.nf
+  ln -s www.acme.com 192.100.66.1
+  ln -s www.joe.acme.com 192.100.66.200
+  ln -s www.jane.acme.com 192.100.66.201
+.fi
+This lets the older HTTP/1.0 browsers find the right subdirectory.
+.PP
+There's an optional alternate step three if you're using multiple-IP
+multihosting: run a separate thttpd process for each hostname, using
+the -h flag to specify which one is which.
+This gives you more flexibility, since you can run each of these processes
+in separate directories, with different throttle files, etc.
+Example:
+.nf
+  thttpd -r -d /usr/www -h www.acme.com
+  thttpd -r -d /usr/www/joe -u joe -h www.joe.acme.com
+  thttpd -r -d /usr/www/jane -u jane -h www.jane.acme.com
+.fi
+But remember, this multiple-process method does not work with CNAME
+multihosting - for that, you must use a single thttpd process with
+the -v flag.
+.SH "CUSTOM ERRORS"
+.PP
+thttpd lets you define your own custom error pages for the various
+HTTP errors.
+There's a separate file for each error number, all stored in one
+special directory.
+The directory name is "errors", at the top of the web directory tree.
+The error files should be named "errNNN.html", where NNN is the error number.
+So for example, to make a custom error page for the authentication failure
+error, which is number 401, you would put your HTML into the file
+"errors/err401.html".
+If no custom error file is found for a given error number, then the
+usual built-in error page is generated.
+.PP
+If you're using the virtual hosts option, you can also have different
+custom error pages for each different virtual host.
+In this case you put another "errors" directory in the top of that
+virtual host's web tree.
+thttpd will look first in the virtual host errors directory, and
+then in the server-wide errors directory, and if neither of those
+has an appropriate error file then it will generate the built-in error.
+.SH "NON-LOCAL REFERRERS"
+.PP
+Sometimes another site on the net will embed your image files in their
+HTML files, which basically means they're stealing your bandwidth.
+You can prevent them from doing this by using non-local referrer filtering.
+With this option, certain files can only be fetched via a local referrer.
+The files have to be referenced by a local web page.
+If a web page on some other site references the files, that fetch will
+be blocked.
+There are three config-file variables for this feature:
+.TP
+.B urlpat
+A wildcard pattern for the URLs that should require a local referrer.
+This is typically just image files, sound files, and so on.
+For example:
+.nf
+  urlpat=**.jpg|**.gif|**.au|**.wav
+.fi
+For most sites, that one setting is all you need to enable referrer filtering.
+.TP
+.B noemptyreferrers
+By default, requests with no referrer at all, or a null referrer, or a
+referrer with no apparent hostname, are allowed.
+With this variable set, such requests are disallowed.
+.TP
+.B localpat
+A wildcard pattern that specifies the local host or hosts.
+This is used to determine if the host in the referrer is local or not.
+If not specified it defaults to the actual local hostname.
+.SH SYMLINKS
+.PP
+thttpd is very picky about symbolic links.
+Before delivering any file, it first checks each element in the path
+to see if it's a symbolic link, and expands them all out to get the final
+actual filename.
+Along the way it checks for things like links with ".." that go above
+the server's directory, and absolute symlinks (ones that start with a /).
+These are prohibited as security holes, so the server returns an
+error page for them.
+This means you can't set up your web directory with a bunch of symlinks
+pointing to individual users' home web directories.
+Instead you do it the other way around - the user web directories are
+real subdirs of the main web directory, and in each user's home
+dir there's a symlink pointing to their actual web dir.
+.PP
+The CGI pattern is also affected - it gets matched against the fully-expanded
+filename.  So, if you have a single CGI directory but then put a symbolic
+link in it pointing somewhere else, that won't work.  The CGI program will be
+treated as a regular file and returned to the client, instead of getting run.
+This could be confusing.
+.SH PERMISSIONS
+.PP
+thttpd is also picky about file permissions.
+It wants data files (HTML, images) to be world readable.
+Readable by the group that the thttpd process runs as is not enough - thttpd
+checks explicitly for the world-readable bit.
+This is so that no one ever gets surprised by a file that's not set
+world-readable and yet somehow is readable by the HTTP server and
+therefore the *whole* world.
+.PP
+The same logic applies to directories.
+As with the standard Unix "ls" program, thttpd will only let you
+look at the contents of a directory if its read bit is on; but
+as with data files, this must be the world-read bit, not just the
+group-read bit.
+.PP
+thttpd also wants the execute bit to be *off* for data files.
+A file that is marked executable but doesn't match the CGI pattern
+might be a script or program that got accidentally left in the
+wrong directory.
+Allowing people to fetch the contents of the file might be a security breach,
+so this is prohibited.
+Of course if an executable file *does* match the CGI pattern, then it
+just gets run as a CGI.
+.PP
+In summary, data files should be mode 644 (rw-r--r--),
+directories should be 755 (rwxr-xr-x) if you want to allow indexing and
+711 (rwx--x--x) to disallow it, and CGI programs should be mode
+755 (rwxr-xr-x) or 711 (rwx--x--x).
+.SH LOGS
+.PP
+thttpd does all of its logging via syslog(3).
+The facility it uses is configurable.
+Aside from error messages, there are only a few log entry types of interest,
+all fairly similar to CERN Common Log Format:
+.nf
+  Aug  6 15:40:34 acme thttpd[583]: 165.113.207.103 - - "GET /file" 200 357
+  Aug  6 15:40:43 acme thttpd[583]: 165.113.207.103 - - "HEAD /file" 200 0
+  Aug  6 15:41:16 acme thttpd[583]: referrer http://www.acme.com/ -> /dir
+  Aug  6 15:41:16 acme thttpd[583]: user-agent Mozilla/1.1N
+.fi
+The package includes a script for translating these log entries info
+CERN-compatible files.
+Note that thttpd does not translate numeric IP addresses into domain names.
+This is both to save time and as a minor security measure (the numeric
+address is harder to spoof).
+.PP
+Relevant config.h option: LOG_FACILITY.
+.PP
+If you'd rather log directly to a file, you can use the -l command-line
+flag.  But note that error messages still go to syslog.
+.SH SIGNALS
+.PP
+thttpd handles a couple of signals, which you can send via the
+standard Unix kill(1) command:
+.TP
+.B INT,TERM
+These signals tell thttpd to shut down immediately.
+Any requests in progress get aborted.
+.TP
+.B USR1
+This signal tells thttpd to shut down as soon as it's done servicing
+all current requests.
+In addition, the network socket it uses to accept new connections gets
+closed immediately, which means a fresh thttpd can be started up
+immediately.
+.TP
+.B USR2
+This signal tells thttpd to generate the statistics syslog messages
+immediately, instead of waiting for the regular hourly update.
+.TP
+.B HUP
+This signal tells thttpd to close and re-open its (non-syslog) log file,
+for instance if you rotated the logs and want it to start using the
+new one.
+This is a little tricky to set up correctly, for instance if you are using
+chroot() then the log file must be within the chroot tree, but it's
+definitely doable.
+.SH "SEE ALSO"
+redirect(8), ssi(8), makeweb(1), htpasswd(1), syslogtocern(8), weblog_parse(1), http_get(1)
+.SH THANKS
+.PP
+Many thanks to contributors, reviewers, testers:
+John LoVerso, Jordan Hayes, Chris Torek, Jim Thompson, Barton Schaffer,
+Geoff Adams, Dan Kegel, John Hascall, Bennett Todd, KIKUCHI Takahiro,
+Catalin Ionescu.
+Special thanks to Craig Leres for substantial debugging and development,
+and for not complaining about my coding style very much.
+.SH AUTHOR
+Copyright © 1995,1998,1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
+All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
diff --git a/thttpd.c b/thttpd.c
new file mode 100644 (file)
index 0000000..3be7546
--- /dev/null
+++ b/thttpd.c
@@ -0,0 +1,2181 @@
+/* thttpd.c - tiny/turbo/throttling HTTP server
+**
+** Copyright © 1995,1998,1999,2000,2001,2015 by
+** Jef Poskanzer <jef@mail.acme.com>. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+
+#include "config.h"
+#include "version.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <pwd.h>
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#include <unistd.h>
+
+#include "fdwatch.h"
+#include "libhttpd.h"
+#include "mmc.h"
+#include "timers.h"
+#include "match.h"
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifndef HAVE_INT64T
+typedef long long int64_t;
+#endif
+
+
+static char* argv0;
+static int debug;
+static unsigned short port;
+static char* dir;
+static char* data_dir;
+static int do_chroot, no_log, no_symlink_check, do_vhost, do_global_passwd;
+static char* cgi_pattern;
+static int cgi_limit;
+static char* url_pattern;
+static int no_empty_referrers;
+static char* local_pattern;
+static char* logfile;
+static char* throttlefile;
+static char* hostname;
+static char* pidfile;
+static char* user;
+static char* charset;
+static char* p3p;
+static int max_age;
+
+
+typedef struct {
+    char* pattern;
+    long max_limit, min_limit;
+    long rate;
+    off_t bytes_since_avg;
+    int num_sending;
+    } throttletab;
+static throttletab* throttles;
+static int numthrottles, maxthrottles;
+
+#define THROTTLE_NOLIMIT -1
+
+
+typedef struct {
+    int conn_state;
+    int next_free_connect;
+    httpd_conn* hc;
+    int tnums[MAXTHROTTLENUMS];         /* throttle indexes */
+    int numtnums;
+    long max_limit, min_limit;
+    time_t started_at, active_at;
+    Timer* wakeup_timer;
+    Timer* linger_timer;
+    long wouldblock_delay;
+    off_t bytes;
+    off_t end_byte_index;
+    off_t next_byte_index;
+    } connecttab;
+static connecttab* connects;
+static int num_connects, max_connects, first_free_connect;
+static int httpd_conn_count;
+
+/* The connection states. */
+#define CNST_FREE 0
+#define CNST_READING 1
+#define CNST_SENDING 2
+#define CNST_PAUSING 3
+#define CNST_LINGERING 4
+
+
+static httpd_server* hs = (httpd_server*) 0;
+int terminate = 0;
+time_t start_time, stats_time;
+long stats_connections;
+off_t stats_bytes;
+int stats_simultaneous;
+
+static volatile int got_hup, got_usr1, watchdog_flag;
+
+
+/* Forwards. */
+static void parse_args( int argc, char** argv );
+static void usage( void );
+static void read_config( char* filename );
+static void value_required( char* name, char* value );
+static void no_value_required( char* name, char* value );
+static char* e_strdup( char* oldstr );
+static void lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P );
+static void read_throttlefile( char* tf );
+static void shut_down( void );
+static int handle_newconnect( struct timeval* tvP, int listen_fd );
+static void handle_read( connecttab* c, struct timeval* tvP );
+static void handle_send( connecttab* c, struct timeval* tvP );
+static void handle_linger( connecttab* c, struct timeval* tvP );
+static int check_throttles( connecttab* c );
+static void clear_throttles( connecttab* c, struct timeval* tvP );
+static void update_throttles( ClientData client_data, struct timeval* nowP );
+static void finish_connection( connecttab* c, struct timeval* tvP );
+static void clear_connection( connecttab* c, struct timeval* tvP );
+static void really_clear_connection( connecttab* c, struct timeval* tvP );
+static void idle( ClientData client_data, struct timeval* nowP );
+static void wakeup_connection( ClientData client_data, struct timeval* nowP );
+static void linger_clear_connection( ClientData client_data, struct timeval* nowP );
+static void occasional( ClientData client_data, struct timeval* nowP );
+#ifdef STATS_TIME
+static void show_stats( ClientData client_data, struct timeval* nowP );
+#endif /* STATS_TIME */
+static void logstats( struct timeval* nowP );
+static void thttpd_logstats( long secs );
+
+
+/* SIGTERM and SIGINT say to exit immediately. */
+static void
+handle_term( int sig )
+    {
+    /* Don't need to set up the handler again, since it's a one-shot. */
+
+    shut_down();
+    syslog( LOG_NOTICE, "exiting due to signal %d", sig );
+    closelog();
+    exit( 1 );
+    }
+
+
+/* SIGCHLD - a chile process exitted, so we need to reap the zombie */
+static void
+handle_chld( int sig )
+    {
+    const int oerrno = errno;
+    pid_t pid;
+    int status;
+
+#ifndef HAVE_SIGSET
+    /* Set up handler again. */
+    (void) signal( SIGCHLD, handle_chld );
+#endif /* ! HAVE_SIGSET */
+
+    /* Reap defunct children until there aren't any more. */
+    for (;;)
+       {
+#ifdef HAVE_WAITPID
+       pid = waitpid( (pid_t) -1, &status, WNOHANG );
+#else /* HAVE_WAITPID */
+       pid = wait3( &status, WNOHANG, (struct rusage*) 0 );
+#endif /* HAVE_WAITPID */
+       if ( (int) pid == 0 )           /* none left */
+           break;
+       if ( (int) pid < 0 )
+           {
+           if ( errno == EINTR || errno == EAGAIN )
+               continue;
+           /* ECHILD shouldn't happen with the WNOHANG option,
+           ** but with some kernels it does anyway.  Ignore it.
+           */
+           if ( errno != ECHILD )
+               syslog( LOG_ERR, "child wait - %m" );
+           break;
+           }
+       /* Decrement the CGI count.  Note that this is not accurate, since
+       ** each CGI can involve two or even three child processes.
+       ** Decrementing for each child means that when there is heavy CGI
+       ** activity, the count will be lower than it should be, and therefore
+       ** more CGIs will be allowed than should be.
+       */
+       if ( hs != (httpd_server*) 0 )
+           {
+           --hs->cgi_count;
+           if ( hs->cgi_count < 0 )
+               hs->cgi_count = 0;
+           }
+       }
+
+    /* Restore previous errno. */
+    errno = oerrno;
+    }
+
+
+/* SIGHUP says to re-open the log file. */
+static void
+handle_hup( int sig )
+    {
+    const int oerrno = errno;
+
+#ifndef HAVE_SIGSET
+    /* Set up handler again. */
+    (void) signal( SIGHUP, handle_hup );
+#endif /* ! HAVE_SIGSET */
+
+    /* Just set a flag that we got the signal. */
+    got_hup = 1;
+
+    /* Restore previous errno. */
+    errno = oerrno;
+    }
+
+
+/* SIGUSR1 says to exit as soon as all current connections are done. */
+static void
+handle_usr1( int sig )
+    {
+    /* Don't need to set up the handler again, since it's a one-shot. */
+
+    if ( num_connects == 0 )
+       {
+       /* If there are no active connections we want to exit immediately
+       ** here.  Not only is it faster, but without any connections the
+       ** main loop won't wake up until the next new connection.
+       */
+       shut_down();
+       syslog( LOG_NOTICE, "exiting" );
+       closelog();
+       exit( 0 );
+       }
+
+    /* Otherwise, just set a flag that we got the signal. */
+    got_usr1 = 1;
+
+    /* Don't need to restore old errno, since we didn't do any syscalls. */
+    }
+
+
+/* SIGUSR2 says to generate the stats syslogs immediately. */
+static void
+handle_usr2( int sig )
+    {
+    const int oerrno = errno;
+
+#ifndef HAVE_SIGSET
+    /* Set up handler again. */
+    (void) signal( SIGUSR2, handle_usr2 );
+#endif /* ! HAVE_SIGSET */
+
+    logstats( (struct timeval*) 0 );
+
+    /* Restore previous errno. */
+    errno = oerrno;
+    }
+
+
+/* SIGALRM is used as a watchdog. */
+static void
+handle_alrm( int sig )
+    {
+    const int oerrno = errno;
+
+    /* If nothing has been happening */
+    if ( ! watchdog_flag )
+       {
+       /* Try changing dirs to someplace we can write. */
+       (void) chdir( "/tmp" );
+       /* Dump core. */
+       abort();
+       }
+    watchdog_flag = 0;
+
+#ifndef HAVE_SIGSET
+    /* Set up handler again. */
+    (void) signal( SIGALRM, handle_alrm );
+#endif /* ! HAVE_SIGSET */
+    /* Set up alarm again. */
+    (void) alarm( OCCASIONAL_TIME * 3 );
+
+    /* Restore previous errno. */
+    errno = oerrno;
+    }
+
+
+static void
+re_open_logfile( void )
+    {
+    FILE* logfp;
+
+    if ( no_log || hs == (httpd_server*) 0 )
+       return;
+
+    /* Re-open the log file. */
+    if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 )
+       {
+       syslog( LOG_NOTICE, "re-opening logfile" );
+       logfp = fopen( logfile, "a" );
+       if ( logfp == (FILE*) 0 )
+           {
+           syslog( LOG_CRIT, "re-opening %.80s - %m", logfile );
+           return;
+           }
+       (void) fcntl( fileno( logfp ), F_SETFD, 1 );
+       httpd_set_logfp( hs, logfp );
+       }
+    }
+
+
+int
+main( int argc, char** argv )
+    {
+    char* cp;
+    struct passwd* pwd;
+    uid_t uid = 32767;
+    gid_t gid = 32767;
+    char cwd[MAXPATHLEN+1];
+    FILE* logfp;
+    int num_ready;
+    int cnum;
+    connecttab* c;
+    httpd_conn* hc;
+    httpd_sockaddr sa4;
+    httpd_sockaddr sa6;
+    int gotv4, gotv6;
+    struct timeval tv;
+
+    argv0 = argv[0];
+
+    cp = strrchr( argv0, '/' );
+    if ( cp != (char*) 0 )
+       ++cp;
+    else
+       cp = argv0;
+    openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY );
+
+    /* Handle command-line arguments. */
+    parse_args( argc, argv );
+
+    /* Read zone info now, in case we chroot(). */
+    tzset();
+
+    /* Look up hostname now, in case we chroot(). */
+    lookup_hostname( &sa4, sizeof(sa4), &gotv4, &sa6, sizeof(sa6), &gotv6 );
+    if ( ! ( gotv4 || gotv6 ) )
+       {
+       syslog( LOG_ERR, "can't find any valid address" );
+       (void) fprintf( stderr, "%s: can't find any valid address\n", argv0 );
+       exit( 1 );
+       }
+
+    /* Throttle file. */
+    numthrottles = 0;
+    maxthrottles = 0;
+    throttles = (throttletab*) 0;
+    if ( throttlefile != (char*) 0 )
+       read_throttlefile( throttlefile );
+
+    /* If we're root and we're going to become another user, get the uid/gid
+    ** now.
+    */
+    if ( getuid() == 0 )
+       {
+       pwd = getpwnam( user );
+       if ( pwd == (struct passwd*) 0 )
+           {
+           syslog( LOG_CRIT, "unknown user - '%.80s'", user );
+           (void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user );
+           exit( 1 );
+           }
+       uid = pwd->pw_uid;
+       gid = pwd->pw_gid;
+       }
+
+    /* Log file. */
+    if ( logfile != (char*) 0 )
+       {
+       if ( strcmp( logfile, "/dev/null" ) == 0 )
+           {
+           no_log = 1;
+           logfp = (FILE*) 0;
+           }
+       else if ( strcmp( logfile, "-" ) == 0 )
+           logfp = stdout;
+       else
+           {
+           logfp = fopen( logfile, "a" );
+           if ( logfp == (FILE*) 0 )
+               {
+               syslog( LOG_CRIT, "%.80s - %m", logfile );
+               perror( logfile );
+               exit( 1 );
+               }
+           if ( logfile[0] != '/' )
+               {
+               syslog( LOG_WARNING, "logfile is not an absolute path, you may not be able to re-open it" );
+               (void) fprintf( stderr, "%s: logfile is not an absolute path, you may not be able to re-open it\n", argv0 );
+               }
+           (void) fcntl( fileno( logfp ), F_SETFD, 1 );
+           if ( getuid() == 0 )
+               {
+               /* If we are root then we chown the log file to the user we'll
+               ** be switching to.
+               */
+               if ( fchown( fileno( logfp ), uid, gid ) < 0 )
+                   {
+                   syslog( LOG_WARNING, "fchown logfile - %m" );
+                   perror( "fchown logfile" );
+                   }
+               }
+           }
+       }
+    else
+       logfp = (FILE*) 0;
+
+    /* Switch directories if requested. */
+    if ( dir != (char*) 0 )
+       {
+       if ( chdir( dir ) < 0 )
+           {
+           syslog( LOG_CRIT, "chdir - %m" );
+           perror( "chdir" );
+           exit( 1 );
+           }
+       }
+#ifdef USE_USER_DIR
+    else if ( getuid() == 0 )
+       {
+       /* No explicit directory was specified, we're root, and the
+       ** USE_USER_DIR option is set - switch to the specified user's
+       ** home dir.
+       */
+       if ( chdir( pwd->pw_dir ) < 0 )
+           {
+           syslog( LOG_CRIT, "chdir - %m" );
+           perror( "chdir" );
+           exit( 1 );
+           }
+       }
+#endif /* USE_USER_DIR */
+
+    /* Get current directory. */
+    (void) getcwd( cwd, sizeof(cwd) - 1 );
+    if ( cwd[strlen( cwd ) - 1] != '/' )
+       (void) strcat( cwd, "/" );
+
+    if ( ! debug )
+       {
+       /* We're not going to use stdin stdout or stderr from here on, so close
+       ** them to save file descriptors.
+       */
+       (void) fclose( stdin );
+       if ( logfp != stdout )
+           (void) fclose( stdout );
+       (void) fclose( stderr );
+
+       /* Daemonize - make ourselves a subprocess. */
+#ifdef HAVE_DAEMON
+       if ( daemon( 1, 1 ) < 0 )
+           {
+           syslog( LOG_CRIT, "daemon - %m" );
+           exit( 1 );
+           }
+#else /* HAVE_DAEMON */
+       switch ( fork() )
+           {
+           case 0:
+           break;
+           case -1:
+           syslog( LOG_CRIT, "fork - %m" );
+           exit( 1 );
+           default:
+           exit( 0 );
+           }
+#ifdef HAVE_SETSID
+        (void) setsid();
+#endif /* HAVE_SETSID */
+#endif /* HAVE_DAEMON */
+       }
+    else
+       {
+       /* Even if we don't daemonize, we still want to disown our parent
+       ** process.
+       */
+#ifdef HAVE_SETSID
+        (void) setsid();
+#endif /* HAVE_SETSID */
+       }
+
+    if ( pidfile != (char*) 0 )
+       {
+       /* Write the PID file. */
+       FILE* pidfp = fopen( pidfile, "w" );
+       if ( pidfp == (FILE*) 0 )
+           {
+           syslog( LOG_CRIT, "%.80s - %m", pidfile );
+           exit( 1 );
+           }
+       (void) fprintf( pidfp, "%d\n", (int) getpid() );
+       (void) fclose( pidfp );
+       }
+
+    /* Initialize the fdwatch package.  Have to do this before chroot,
+    ** if /dev/poll is used.
+    */
+    max_connects = fdwatch_get_nfiles();
+    if ( max_connects < 0 )
+       {
+       syslog( LOG_CRIT, "fdwatch initialization failure" );
+       exit( 1 );
+       }
+    max_connects -= SPARE_FDS;
+
+    /* Chroot if requested. */
+    if ( do_chroot )
+       {
+       if ( chroot( cwd ) < 0 )
+           {
+           syslog( LOG_CRIT, "chroot - %m" );
+           perror( "chroot" );
+           exit( 1 );
+           }
+       /* If we're logging and the logfile's pathname begins with the
+       ** chroot tree's pathname, then elide the chroot pathname so
+       ** that the logfile pathname still works from inside the chroot
+       ** tree.
+       */
+       if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 )
+           {
+           if ( strncmp( logfile, cwd, strlen( cwd ) ) == 0 )
+               {
+               (void) ol_strcpy( logfile, &logfile[strlen( cwd ) - 1] );
+               /* (We already guaranteed that cwd ends with a slash, so leaving
+               ** that slash in logfile makes it an absolute pathname within
+               ** the chroot tree.)
+               */
+               }
+           else
+               {
+               syslog( LOG_WARNING, "logfile is not within the chroot tree, you will not be able to re-open it" );
+               (void) fprintf( stderr, "%s: logfile is not within the chroot tree, you will not be able to re-open it\n", argv0 );
+               }
+           }
+       (void) strcpy( cwd, "/" );
+       /* Always chdir to / after a chroot. */
+       if ( chdir( cwd ) < 0 )
+           {
+           syslog( LOG_CRIT, "chroot chdir - %m" );
+           perror( "chroot chdir" );
+           exit( 1 );
+           }
+       }
+
+    /* Switch directories again if requested. */
+    if ( data_dir != (char*) 0 )
+       {
+       if ( chdir( data_dir ) < 0 )
+           {
+           syslog( LOG_CRIT, "data_dir chdir - %m" );
+           perror( "data_dir chdir" );
+           exit( 1 );
+           }
+       }
+
+    /* Set up to catch signals. */
+#ifdef HAVE_SIGSET
+    (void) sigset( SIGTERM, handle_term );
+    (void) sigset( SIGINT, handle_term );
+    (void) sigset( SIGCHLD, handle_chld );
+    (void) sigset( SIGPIPE, SIG_IGN );          /* get EPIPE instead */
+    (void) sigset( SIGHUP, handle_hup );
+    (void) sigset( SIGUSR1, handle_usr1 );
+    (void) sigset( SIGUSR2, handle_usr2 );
+    (void) sigset( SIGALRM, handle_alrm );
+#else /* HAVE_SIGSET */
+    (void) signal( SIGTERM, handle_term );
+    (void) signal( SIGINT, handle_term );
+    (void) signal( SIGCHLD, handle_chld );
+    (void) signal( SIGPIPE, SIG_IGN );          /* get EPIPE instead */
+    (void) signal( SIGHUP, handle_hup );
+    (void) signal( SIGUSR1, handle_usr1 );
+    (void) signal( SIGUSR2, handle_usr2 );
+    (void) signal( SIGALRM, handle_alrm );
+#endif /* HAVE_SIGSET */
+    got_hup = 0;
+    got_usr1 = 0;
+    watchdog_flag = 0;
+    (void) alarm( OCCASIONAL_TIME * 3 );
+
+    /* Initialize the timer package. */
+    tmr_init();
+
+    /* Initialize the HTTP layer.  Got to do this before giving up root,
+    ** so that we can bind to a privileged port.
+    */
+    hs = httpd_initialize(
+       hostname,
+       gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0,
+       port, cgi_pattern, cgi_limit, charset, p3p, max_age, cwd, no_log, logfp,
+       no_symlink_check, do_vhost, do_global_passwd, url_pattern,
+       local_pattern, no_empty_referrers );
+    if ( hs == (httpd_server*) 0 )
+       exit( 1 );
+
+    /* Set up the occasional timer. */
+    if ( tmr_create( (struct timeval*) 0, occasional, JunkClientData, OCCASIONAL_TIME * 1000L, 1 ) == (Timer*) 0 )
+       {
+       syslog( LOG_CRIT, "tmr_create(occasional) failed" );
+       exit( 1 );
+       }
+    /* Set up the idle timer. */
+    if ( tmr_create( (struct timeval*) 0, idle, JunkClientData, 5 * 1000L, 1 ) == (Timer*) 0 )
+       {
+       syslog( LOG_CRIT, "tmr_create(idle) failed" );
+       exit( 1 );
+       }
+    if ( numthrottles > 0 )
+       {
+       /* Set up the throttles timer. */
+       if ( tmr_create( (struct timeval*) 0, update_throttles, JunkClientData, THROTTLE_TIME * 1000L, 1 ) == (Timer*) 0 )
+           {
+           syslog( LOG_CRIT, "tmr_create(update_throttles) failed" );
+           exit( 1 );
+           }
+       }
+#ifdef STATS_TIME
+    /* Set up the stats timer. */
+    if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 )
+       {
+       syslog( LOG_CRIT, "tmr_create(show_stats) failed" );
+       exit( 1 );
+       }
+#endif /* STATS_TIME */
+    start_time = stats_time = time( (time_t*) 0 );
+    stats_connections = 0;
+    stats_bytes = 0;
+    stats_simultaneous = 0;
+
+    /* If we're root, try to become someone else. */
+    if ( getuid() == 0 )
+       {
+       /* Set aux groups to null. */
+       if ( setgroups( 0, (const gid_t*) 0 ) < 0 )
+           {
+           syslog( LOG_CRIT, "setgroups - %m" );
+           exit( 1 );
+           }
+       /* Set primary group. */
+       if ( setgid( gid ) < 0 )
+           {
+           syslog( LOG_CRIT, "setgid - %m" );
+           exit( 1 );
+           }
+       /* Try setting aux groups correctly - not critical if this fails. */
+       if ( initgroups( user, gid ) < 0 )
+           syslog( LOG_WARNING, "initgroups - %m" );
+#ifdef HAVE_SETLOGIN
+       /* Set login name. */
+        (void) setlogin( user );
+#endif /* HAVE_SETLOGIN */
+       /* Set uid. */
+       if ( setuid( uid ) < 0 )
+           {
+           syslog( LOG_CRIT, "setuid - %m" );
+           exit( 1 );
+           }
+       /* Check for unnecessary security exposure. */
+       if ( ! do_chroot )
+           syslog(
+               LOG_WARNING,
+               "started as root without requesting chroot(), warning only" );
+       }
+
+    /* Initialize our connections table. */
+    connects = NEW( connecttab, max_connects );
+    if ( connects == (connecttab*) 0 )
+       {
+       syslog( LOG_CRIT, "out of memory allocating a connecttab" );
+       exit( 1 );
+       }
+    for ( cnum = 0; cnum < max_connects; ++cnum )
+       {
+       connects[cnum].conn_state = CNST_FREE;
+       connects[cnum].next_free_connect = cnum + 1;
+       connects[cnum].hc = (httpd_conn*) 0;
+       }
+    connects[max_connects - 1].next_free_connect = -1; /* end of link list */
+    first_free_connect = 0;
+    num_connects = 0;
+    httpd_conn_count = 0;
+
+    if ( hs != (httpd_server*) 0 )
+       {
+       if ( hs->listen4_fd != -1 )
+           fdwatch_add_fd( hs->listen4_fd, (void*) 0, FDW_READ );
+       if ( hs->listen6_fd != -1 )
+           fdwatch_add_fd( hs->listen6_fd, (void*) 0, FDW_READ );
+       }
+
+    /* Main loop. */
+    (void) gettimeofday( &tv, (struct timezone*) 0 );
+    while ( ( ! terminate ) || num_connects > 0 )
+       {
+       /* Do we need to re-open the log file? */
+       if ( got_hup )
+           {
+           re_open_logfile();
+           got_hup = 0;
+           }
+
+       /* Do the fd watch. */
+       num_ready = fdwatch( tmr_mstimeout( &tv ) );
+       if ( num_ready < 0 )
+           {
+           if ( errno == EINTR || errno == EAGAIN )
+               continue;       /* try again */
+           syslog( LOG_ERR, "fdwatch - %m" );
+           exit( 1 );
+           }
+       (void) gettimeofday( &tv, (struct timezone*) 0 );
+
+       if ( num_ready == 0 )
+           {
+           /* No fd's are ready - run the timers. */
+           tmr_run( &tv );
+           continue;
+           }
+
+       /* Is it a new connection? */
+       if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 &&
+            fdwatch_check_fd( hs->listen6_fd ) )
+           {
+           if ( handle_newconnect( &tv, hs->listen6_fd ) )
+               /* Go around the loop and do another fdwatch, rather than
+               ** dropping through and processing existing connections.
+               ** New connections always get priority.
+               */
+               continue;
+           }
+       if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 &&
+            fdwatch_check_fd( hs->listen4_fd ) )
+           {
+           if ( handle_newconnect( &tv, hs->listen4_fd ) )
+               /* Go around the loop and do another fdwatch, rather than
+               ** dropping through and processing existing connections.
+               ** New connections always get priority.
+               */
+               continue;
+           }
+
+       /* Find the connections that need servicing. */
+       while ( ( c = (connecttab*) fdwatch_get_next_client_data() ) != (connecttab*) -1 )
+           {
+           if ( c == (connecttab*) 0 )
+               continue;
+           hc = c->hc;
+           if ( ! fdwatch_check_fd( hc->conn_fd ) )
+               /* Something went wrong. */
+               clear_connection( c, &tv );
+           else
+               switch ( c->conn_state )
+                   {
+                   case CNST_READING: handle_read( c, &tv ); break;
+                   case CNST_SENDING: handle_send( c, &tv ); break;
+                   case CNST_LINGERING: handle_linger( c, &tv ); break;
+                   }
+           }
+       tmr_run( &tv );
+
+       if ( got_usr1 && ! terminate )
+           {
+           terminate = 1;
+           if ( hs != (httpd_server*) 0 )
+               {
+               if ( hs->listen4_fd != -1 )
+                   fdwatch_del_fd( hs->listen4_fd );
+               if ( hs->listen6_fd != -1 )
+                   fdwatch_del_fd( hs->listen6_fd );
+               httpd_unlisten( hs );
+               }
+           }
+       }
+
+    /* The main loop terminated. */
+    shut_down();
+    syslog( LOG_NOTICE, "exiting" );
+    closelog();
+    exit( 0 );
+    }
+
+
+static void
+parse_args( int argc, char** argv )
+    {
+    int argn;
+
+    debug = 0;
+    port = DEFAULT_PORT;
+    dir = (char*) 0;
+    data_dir = (char*) 0;
+#ifdef ALWAYS_CHROOT
+    do_chroot = 1;
+#else /* ALWAYS_CHROOT */
+    do_chroot = 0;
+#endif /* ALWAYS_CHROOT */
+    no_log = 0;
+    no_symlink_check = do_chroot;
+#ifdef ALWAYS_VHOST
+    do_vhost = 1;
+#else /* ALWAYS_VHOST */
+    do_vhost = 0;
+#endif /* ALWAYS_VHOST */
+#ifdef ALWAYS_GLOBAL_PASSWD
+    do_global_passwd = 1;
+#else /* ALWAYS_GLOBAL_PASSWD */
+    do_global_passwd = 0;
+#endif /* ALWAYS_GLOBAL_PASSWD */
+#ifdef CGI_PATTERN
+    cgi_pattern = CGI_PATTERN;
+#else /* CGI_PATTERN */
+    cgi_pattern = (char*) 0;
+#endif /* CGI_PATTERN */
+#ifdef CGI_LIMIT
+    cgi_limit = CGI_LIMIT;
+#else /* CGI_LIMIT */
+    cgi_limit = 0;
+#endif /* CGI_LIMIT */
+    url_pattern = (char*) 0;
+    no_empty_referrers = 0;
+    local_pattern = (char*) 0;
+    throttlefile = (char*) 0;
+    hostname = (char*) 0;
+    logfile = (char*) 0;
+    pidfile = (char*) 0;
+    user = DEFAULT_USER;
+    charset = DEFAULT_CHARSET;
+    p3p = "";
+    max_age = -1;
+    argn = 1;
+    while ( argn < argc && argv[argn][0] == '-' )
+       {
+       if ( strcmp( argv[argn], "-V" ) == 0 )
+           {
+           (void) printf( "%s\n", SERVER_SOFTWARE );
+           exit( 0 );
+           }
+       else if ( strcmp( argv[argn], "-C" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           read_config( argv[argn] );
+           }
+       else if ( strcmp( argv[argn], "-p" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           port = (unsigned short) atoi( argv[argn] );
+           }
+       else if ( strcmp( argv[argn], "-d" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           dir = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-r" ) == 0 )
+           {
+           do_chroot = 1;
+           no_symlink_check = 1;
+           }
+       else if ( strcmp( argv[argn], "-nor" ) == 0 )
+           {
+           do_chroot = 0;
+           no_symlink_check = 0;
+           }
+       else if ( strcmp( argv[argn], "-dd" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           data_dir = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-s" ) == 0 )
+           no_symlink_check = 0;
+       else if ( strcmp( argv[argn], "-nos" ) == 0 )
+           no_symlink_check = 1;
+       else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           user = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           cgi_pattern = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-t" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           throttlefile = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-h" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           hostname = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-l" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           logfile = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-v" ) == 0 )
+           do_vhost = 1;
+       else if ( strcmp( argv[argn], "-nov" ) == 0 )
+           do_vhost = 0;
+       else if ( strcmp( argv[argn], "-g" ) == 0 )
+           do_global_passwd = 1;
+       else if ( strcmp( argv[argn], "-nog" ) == 0 )
+           do_global_passwd = 0;
+       else if ( strcmp( argv[argn], "-i" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           pidfile = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-T" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           charset = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-P" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           p3p = argv[argn];
+           }
+       else if ( strcmp( argv[argn], "-M" ) == 0 && argn + 1 < argc )
+           {
+           ++argn;
+           max_age = atoi( argv[argn] );
+           }
+       else if ( strcmp( argv[argn], "-D" ) == 0 )
+           debug = 1;
+       else
+           usage();
+       ++argn;
+       }
+    if ( argn != argc )
+       usage();
+    }
+
+
+static void
+usage( void )
+    {
+    (void) fprintf( stderr,
+"usage:  %s [-C configfile] [-p port] [-d dir] [-r|-nor] [-dd data_dir] [-s|-nos] [-v|-nov] [-g|-nog] [-u user] [-c cgipat] [-t throttles] [-h host] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage] [-V] [-D]\n",
+       argv0 );
+    exit( 1 );
+    }
+
+
+static void
+read_config( char* filename )
+    {
+    FILE* fp;
+    char line[10000];
+    char* cp;
+    char* cp2;
+    char* name;
+    char* value;
+
+    fp = fopen( filename, "r" );
+    if ( fp == (FILE*) 0 )
+       {
+       perror( filename );
+       exit( 1 );
+       }
+
+    while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
+       {
+       /* Trim comments. */
+       if ( ( cp = strchr( line, '#' ) ) != (char*) 0 )
+           *cp = '\0';
+
+       /* Skip leading whitespace. */
+       cp = line;
+       cp += strspn( cp, " \t\n\r" );
+
+       /* Split line into words. */
+       while ( *cp != '\0' )
+           {
+           /* Find next whitespace. */
+           cp2 = cp + strcspn( cp, " \t\n\r" );
+           /* Insert EOS and advance next-word pointer. */
+           while ( *cp2 == ' ' || *cp2 == '\t' || *cp2 == '\n' || *cp2 == '\r' )
+               *cp2++ = '\0';
+           /* Split into name and value. */
+           name = cp;
+           value = strchr( name, '=' );
+           if ( value != (char*) 0 )
+               *value++ = '\0';
+           /* Interpret. */
+           if ( strcasecmp( name, "debug" ) == 0 )
+               {
+               no_value_required( name, value );
+               debug = 1;
+               }
+           else if ( strcasecmp( name, "port" ) == 0 )
+               {
+               value_required( name, value );
+               port = (unsigned short) atoi( value );
+               }
+           else if ( strcasecmp( name, "dir" ) == 0 )
+               {
+               value_required( name, value );
+               dir = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "chroot" ) == 0 )
+               {
+               no_value_required( name, value );
+               do_chroot = 1;
+               no_symlink_check = 1;
+               }
+           else if ( strcasecmp( name, "nochroot" ) == 0 )
+               {
+               no_value_required( name, value );
+               do_chroot = 0;
+               no_symlink_check = 0;
+               }
+           else if ( strcasecmp( name, "data_dir" ) == 0 )
+               {
+               value_required( name, value );
+               data_dir = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "nosymlinkcheck" ) == 0 )
+               {
+               no_value_required( name, value );
+               no_symlink_check = 1;
+               }
+           else if ( strcasecmp( name, "symlinkcheck" ) == 0 )
+               {
+               no_value_required( name, value );
+               no_symlink_check = 0;
+               }
+           else if ( strcasecmp( name, "user" ) == 0 )
+               {
+               value_required( name, value );
+               user = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "cgipat" ) == 0 )
+               {
+               value_required( name, value );
+               cgi_pattern = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "cgilimit" ) == 0 )
+               {
+               value_required( name, value );
+               cgi_limit = atoi( value );
+               }
+           else if ( strcasecmp( name, "urlpat" ) == 0 )
+               {
+               value_required( name, value );
+               url_pattern = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "noemptyreferers" ) == 0 ||
+                     strcasecmp( name, "noemptyreferrers" ) == 0 )
+               {
+               no_value_required( name, value );
+               no_empty_referrers = 1;
+               }
+           else if ( strcasecmp( name, "localpat" ) == 0 )
+               {
+               value_required( name, value );
+               local_pattern = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "throttles" ) == 0 )
+               {
+               value_required( name, value );
+               throttlefile = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "host" ) == 0 )
+               {
+               value_required( name, value );
+               hostname = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "logfile" ) == 0 )
+               {
+               value_required( name, value );
+               logfile = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "vhost" ) == 0 )
+               {
+               no_value_required( name, value );
+               do_vhost = 1;
+               }
+           else if ( strcasecmp( name, "novhost" ) == 0 )
+               {
+               no_value_required( name, value );
+               do_vhost = 0;
+               }
+           else if ( strcasecmp( name, "globalpasswd" ) == 0 )
+               {
+               no_value_required( name, value );
+               do_global_passwd = 1;
+               }
+           else if ( strcasecmp( name, "noglobalpasswd" ) == 0 )
+               {
+               no_value_required( name, value );
+               do_global_passwd = 0;
+               }
+           else if ( strcasecmp( name, "pidfile" ) == 0 )
+               {
+               value_required( name, value );
+               pidfile = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "charset" ) == 0 )
+               {
+               value_required( name, value );
+               charset = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "p3p" ) == 0 )
+               {
+               value_required( name, value );
+               p3p = e_strdup( value );
+               }
+           else if ( strcasecmp( name, "max_age" ) == 0 )
+               {
+               value_required( name, value );
+               max_age = atoi( value );
+               }
+           else
+               {
+               (void) fprintf(
+                   stderr, "%s: unknown config option '%s'\n", argv0, name );
+               exit( 1 );
+               }
+
+           /* Advance to next word. */
+           cp = cp2;
+           cp += strspn( cp, " \t\n\r" );
+           }
+       }
+
+    (void) fclose( fp );
+    }
+
+
+static void
+value_required( char* name, char* value )
+    {
+    if ( value == (char*) 0 )
+       {
+       (void) fprintf(
+           stderr, "%s: value required for %s option\n", argv0, name );
+       exit( 1 );
+       }
+    }
+
+
+static void
+no_value_required( char* name, char* value )
+    {
+    if ( value != (char*) 0 )
+       {
+       (void) fprintf(
+           stderr, "%s: no value required for %s option\n",
+           argv0, name );
+       exit( 1 );
+       }
+    }
+
+
+static char*
+e_strdup( char* oldstr )
+    {
+    char* newstr;
+
+    newstr = strdup( oldstr );
+    if ( newstr == (char*) 0 )
+       {
+       syslog( LOG_CRIT, "out of memory copying a string" );
+       (void) fprintf( stderr, "%s: out of memory copying a string\n", argv0 );
+       exit( 1 );
+       }
+    return newstr;
+    }
+
+
+static void
+lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P )
+    {
+#ifdef USE_IPV6
+
+    struct addrinfo hints;
+    char portstr[10];
+    int gaierr;
+    struct addrinfo* ai;
+    struct addrinfo* ai2;
+    struct addrinfo* aiv6;
+    struct addrinfo* aiv4;
+
+    (void) memset( &hints, 0, sizeof(hints) );
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_flags = AI_PASSIVE;
+    hints.ai_socktype = SOCK_STREAM;
+    (void) snprintf( portstr, sizeof(portstr), "%d", (int) port );
+    if ( (gaierr = getaddrinfo( hostname, portstr, &hints, &ai )) != 0 )
+       {
+       syslog(
+           LOG_CRIT, "getaddrinfo %.80s - %.80s",
+           hostname, gai_strerror( gaierr ) );
+       (void) fprintf(
+           stderr, "%s: getaddrinfo %s - %s\n",
+           argv0, hostname, gai_strerror( gaierr ) );
+       exit( 1 );
+       }
+
+    /* Find the first IPv6 and IPv4 entries. */
+    aiv6 = (struct addrinfo*) 0;
+    aiv4 = (struct addrinfo*) 0;
+    for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
+       {
+       switch ( ai2->ai_family )
+           {
+           case AF_INET6:
+           if ( aiv6 == (struct addrinfo*) 0 )
+               aiv6 = ai2;
+           break;
+           case AF_INET:
+           if ( aiv4 == (struct addrinfo*) 0 )
+               aiv4 = ai2;
+           break;
+           }
+       }
+
+    if ( aiv6 == (struct addrinfo*) 0 )
+       *gotv6P = 0;
+    else
+       {
+       if ( sa6_len < aiv6->ai_addrlen )
+           {
+           syslog(
+               LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)",
+               hostname, (unsigned long) sa6_len,
+               (unsigned long) aiv6->ai_addrlen );
+           exit( 1 );
+           }
+       (void) memset( sa6P, 0, sa6_len );
+       (void) memmove( sa6P, aiv6->ai_addr, aiv6->ai_addrlen );
+       *gotv6P = 1;
+       }
+
+    if ( aiv4 == (struct addrinfo*) 0 )
+       *gotv4P = 0;
+    else
+       {
+       if ( sa4_len < aiv4->ai_addrlen )
+           {
+           syslog(
+               LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)",
+               hostname, (unsigned long) sa4_len,
+               (unsigned long) aiv4->ai_addrlen );
+           exit( 1 );
+           }
+       (void) memset( sa4P, 0, sa4_len );
+       (void) memmove( sa4P, aiv4->ai_addr, aiv4->ai_addrlen );
+       *gotv4P = 1;
+       }
+
+    freeaddrinfo( ai );
+
+#else /* USE_IPV6 */
+
+    struct hostent* he;
+
+    *gotv6P = 0;
+
+    (void) memset( sa4P, 0, sa4_len );
+    sa4P->sa.sa_family = AF_INET;
+    if ( hostname == (char*) 0 )
+       sa4P->sa_in.sin_addr.s_addr = htonl( INADDR_ANY );
+    else
+       {
+       sa4P->sa_in.sin_addr.s_addr = inet_addr( hostname );
+       if ( (int) sa4P->sa_in.sin_addr.s_addr == -1 )
+           {
+           he = gethostbyname( hostname );
+           if ( he == (struct hostent*) 0 )
+               {
+#ifdef HAVE_HSTRERROR
+               syslog(
+                   LOG_CRIT, "gethostbyname %.80s - %.80s",
+                   hostname, hstrerror( h_errno ) );
+               (void) fprintf(
+                   stderr, "%s: gethostbyname %s - %s\n",
+                   argv0, hostname, hstrerror( h_errno ) );
+#else /* HAVE_HSTRERROR */
+               syslog( LOG_CRIT, "gethostbyname %.80s failed", hostname );
+               (void) fprintf(
+                   stderr, "%s: gethostbyname %s failed\n", argv0, hostname );
+#endif /* HAVE_HSTRERROR */
+               exit( 1 );
+               }
+           if ( he->h_addrtype != AF_INET )
+               {
+               syslog( LOG_CRIT, "%.80s - non-IP network address", hostname );
+               (void) fprintf(
+                   stderr, "%s: %s - non-IP network address\n",
+                   argv0, hostname );
+               exit( 1 );
+               }
+           (void) memmove(
+               &sa4P->sa_in.sin_addr.s_addr, he->h_addr, he->h_length );
+           }
+       }
+    sa4P->sa_in.sin_port = htons( port );
+    *gotv4P = 1;
+
+#endif /* USE_IPV6 */
+    }
+
+
+static void
+read_throttlefile( char* tf )
+    {
+    FILE* fp;
+    char buf[5000];
+    char* cp;
+    int len;
+    char pattern[5000];
+    long max_limit, min_limit;
+    struct timeval tv;
+
+    fp = fopen( tf, "r" );
+    if ( fp == (FILE*) 0 )
+       {
+       syslog( LOG_CRIT, "%.80s - %m", tf );
+       perror( tf );
+       exit( 1 );
+       }
+
+    (void) gettimeofday( &tv, (struct timezone*) 0 );
+
+    while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 )
+       {
+       /* Nuke comments. */
+       cp = strchr( buf, '#' );
+       if ( cp != (char*) 0 )
+           *cp = '\0';
+
+       /* Nuke trailing whitespace. */
+       len = strlen( buf );
+       while ( len > 0 &&
+               ( buf[len-1] == ' ' || buf[len-1] == '\t' ||
+                 buf[len-1] == '\n' || buf[len-1] == '\r' ) )
+           buf[--len] = '\0';
+
+       /* Ignore empty lines. */
+       if ( len == 0 )
+           continue;
+
+       /* Parse line. */
+       if ( sscanf( buf, " %4900[^ \t] %ld-%ld", pattern, &min_limit, &max_limit ) == 3 )
+           {}
+       else if ( sscanf( buf, " %4900[^ \t] %ld", pattern, &max_limit ) == 2 )
+           min_limit = 0;
+       else
+           {
+           syslog( LOG_CRIT,
+               "unparsable line in %.80s - %.80s", tf, buf );
+           (void) fprintf( stderr,
+               "%s: unparsable line in %.80s - %.80s\n",
+               argv0, tf, buf );
+           continue;
+           }
+
+       /* Nuke any leading slashes in pattern. */
+       if ( pattern[0] == '/' )
+           (void) ol_strcpy( pattern, &pattern[1] );
+       while ( ( cp = strstr( pattern, "|/" ) ) != (char*) 0 )
+           (void) ol_strcpy( cp + 1, cp + 2 );
+
+       /* Check for room in throttles. */
+       if ( numthrottles >= maxthrottles )
+           {
+           if ( maxthrottles == 0 )
+               {
+               maxthrottles = 100;     /* arbitrary */
+               throttles = NEW( throttletab, maxthrottles );
+               }
+           else
+               {
+               maxthrottles *= 2;
+               throttles = RENEW( throttles, throttletab, maxthrottles );
+               }
+           if ( throttles == (throttletab*) 0 )
+               {
+               syslog( LOG_CRIT, "out of memory allocating a throttletab" );
+               (void) fprintf(
+                   stderr, "%s: out of memory allocating a throttletab\n",
+                   argv0 );
+               exit( 1 );
+               }
+           }
+
+       /* Add to table. */
+       throttles[numthrottles].pattern = e_strdup( pattern );
+       throttles[numthrottles].max_limit = max_limit;
+       throttles[numthrottles].min_limit = min_limit;
+       throttles[numthrottles].rate = 0;
+       throttles[numthrottles].bytes_since_avg = 0;
+       throttles[numthrottles].num_sending = 0;
+
+       ++numthrottles;
+       }
+    (void) fclose( fp );
+    }
+
+
+static void
+shut_down( void )
+    {
+    int cnum;
+    struct timeval tv;
+
+    (void) gettimeofday( &tv, (struct timezone*) 0 );
+    logstats( &tv );
+    for ( cnum = 0; cnum < max_connects; ++cnum )
+       {
+       if ( connects[cnum].conn_state != CNST_FREE )
+           httpd_close_conn( connects[cnum].hc, &tv );
+       if ( connects[cnum].hc != (httpd_conn*) 0 )
+           {
+           httpd_destroy_conn( connects[cnum].hc );
+           free( (void*) connects[cnum].hc );
+           --httpd_conn_count;
+           connects[cnum].hc = (httpd_conn*) 0;
+           }
+       }
+    if ( hs != (httpd_server*) 0 )
+       {
+       httpd_server* ths = hs;
+       hs = (httpd_server*) 0;
+       if ( ths->listen4_fd != -1 )
+           fdwatch_del_fd( ths->listen4_fd );
+       if ( ths->listen6_fd != -1 )
+           fdwatch_del_fd( ths->listen6_fd );
+       httpd_terminate( ths );
+       }
+    mmc_term();
+    tmr_term();
+    free( (void*) connects );
+    if ( throttles != (throttletab*) 0 )
+       free( (void*) throttles );
+    }
+
+
+static int
+handle_newconnect( struct timeval* tvP, int listen_fd )
+    {
+    connecttab* c;
+    ClientData client_data;
+
+    /* This loops until the accept() fails, trying to start new
+    ** connections as fast as possible so we don't overrun the
+    ** listen queue.
+    */
+    for (;;)
+       {
+       /* Is there room in the connection table? */
+       if ( num_connects >= max_connects )
+           {
+           /* Out of connection slots.  Run the timers, then the
+           ** existing connections, and maybe we'll free up a slot
+           ** by the time we get back here.
+           */
+           syslog( LOG_WARNING, "too many connections!" );
+           tmr_run( tvP );
+           return 0;
+           }
+       /* Get the first free connection entry off the free list. */
+       if ( first_free_connect == -1 || connects[first_free_connect].conn_state != CNST_FREE )
+           {
+           syslog( LOG_CRIT, "the connects free list is messed up" );
+           exit( 1 );
+           }
+       c = &connects[first_free_connect];
+       /* Make the httpd_conn if necessary. */
+       if ( c->hc == (httpd_conn*) 0 )
+           {
+           c->hc = NEW( httpd_conn, 1 );
+           if ( c->hc == (httpd_conn*) 0 )
+               {
+               syslog( LOG_CRIT, "out of memory allocating an httpd_conn" );
+               exit( 1 );
+               }
+           c->hc->initialized = 0;
+           ++httpd_conn_count;
+           }
+
+       /* Get the connection. */
+       switch ( httpd_get_conn( hs, listen_fd, c->hc ) )
+           {
+           /* Some error happened.  Run the timers, then the
+           ** existing connections.  Maybe the error will clear.
+           */
+           case GC_FAIL:
+           tmr_run( tvP );
+           return 0;
+
+           /* No more connections to accept for now. */
+           case GC_NO_MORE:
+           return 1;
+           }
+       c->conn_state = CNST_READING;
+       /* Pop it off the free list. */
+       first_free_connect = c->next_free_connect;
+       c->next_free_connect = -1;
+       ++num_connects;
+       client_data.p = c;
+       c->active_at = tvP->tv_sec;
+       c->wakeup_timer = (Timer*) 0;
+       c->linger_timer = (Timer*) 0;
+       c->next_byte_index = 0;
+       c->numtnums = 0;
+
+       /* Set the connection file descriptor to no-delay mode. */
+       httpd_set_ndelay( c->hc->conn_fd );
+
+       fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
+
+       ++stats_connections;
+       if ( num_connects > stats_simultaneous )
+           stats_simultaneous = num_connects;
+       }
+    }
+
+
+static void
+handle_read( connecttab* c, struct timeval* tvP )
+    {
+    int sz;
+    ClientData client_data;
+    httpd_conn* hc = c->hc;
+
+    /* Is there room in our buffer to read more bytes? */
+    if ( hc->read_idx >= hc->read_size )
+       {
+       if ( hc->read_size > 5000 )
+           {
+           httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+           finish_connection( c, tvP );
+           return;
+           }
+       httpd_realloc_str(
+           &hc->read_buf, &hc->read_size, hc->read_size + 1000 );
+       }
+
+    /* Read some more bytes. */
+    sz = read(
+       hc->conn_fd, &(hc->read_buf[hc->read_idx]),
+       hc->read_size - hc->read_idx );
+    if ( sz == 0 )
+       {
+       httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+       finish_connection( c, tvP );
+       return;
+       }
+    if ( sz < 0 )
+       {
+       /* Ignore EINTR and EAGAIN.  Also ignore EWOULDBLOCK.  At first glance
+       ** you would think that connections returned by fdwatch as readable
+       ** should never give an EWOULDBLOCK; however, this apparently can
+       ** happen if a packet gets garbled.
+       */
+       if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
+           return;
+       httpd_send_err(
+           hc, 400, httpd_err400title, "", httpd_err400form, "" );
+       finish_connection( c, tvP );
+       return;
+       }
+    hc->read_idx += sz;
+    c->active_at = tvP->tv_sec;
+
+    /* Do we have a complete request yet? */
+    switch ( httpd_got_request( hc ) )
+       {
+       case GR_NO_REQUEST:
+       return;
+       case GR_BAD_REQUEST:
+       httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+       finish_connection( c, tvP );
+       return;
+       }
+
+    /* Yes.  Try parsing and resolving it. */
+    if ( httpd_parse_request( hc ) < 0 )
+       {
+       finish_connection( c, tvP );
+       return;
+       }
+
+    /* Check the throttle table */
+    if ( ! check_throttles( c ) )
+       {
+       httpd_send_err(
+           hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl );
+       finish_connection( c, tvP );
+       return;
+       }
+
+    /* Start the connection going. */
+    if ( httpd_start_request( hc, tvP ) < 0 )
+       {
+       /* Something went wrong.  Close down the connection. */
+       finish_connection( c, tvP );
+       return;
+       }
+
+    /* Fill in end_byte_index. */
+    if ( hc->got_range )
+       {
+       c->next_byte_index = hc->first_byte_index;
+       c->end_byte_index = hc->last_byte_index + 1;
+       }
+    else if ( hc->bytes_to_send < 0 )
+       c->end_byte_index = 0;
+    else
+       c->end_byte_index = hc->bytes_to_send;
+
+    /* Check if it's already handled. */
+    if ( hc->file_address == (char*) 0 )
+       {
+       /* No file address means someone else is handling it. */
+       int tind;
+       for ( tind = 0; tind < c->numtnums; ++tind )
+           throttles[c->tnums[tind]].bytes_since_avg += hc->bytes_sent;
+       c->next_byte_index = hc->bytes_sent;
+       finish_connection( c, tvP );
+       return;
+       }
+    if ( c->next_byte_index >= c->end_byte_index )
+       {
+       /* There's nothing to send. */
+       finish_connection( c, tvP );
+       return;
+       }
+
+    /* Cool, we have a valid connection and a file to send to it. */
+    c->conn_state = CNST_SENDING;
+    c->started_at = tvP->tv_sec;
+    c->wouldblock_delay = 0;
+    client_data.p = c;
+
+    fdwatch_del_fd( hc->conn_fd );
+    fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );
+    }
+
+
+static void
+handle_send( connecttab* c, struct timeval* tvP )
+    {
+    size_t max_bytes;
+    int sz, coast;
+    ClientData client_data;
+    time_t elapsed;
+    httpd_conn* hc = c->hc;
+    int tind;
+
+    if ( c->max_limit == THROTTLE_NOLIMIT )
+       max_bytes = 1000000000L;
+    else
+       max_bytes = c->max_limit / 4;   /* send at most 1/4 seconds worth */
+
+    /* Do we need to write the headers first? */
+    if ( hc->responselen == 0 )
+       {
+       /* No, just write the file. */
+       sz = write(
+           hc->conn_fd, &(hc->file_address[c->next_byte_index]),
+           MIN( c->end_byte_index - c->next_byte_index, max_bytes ) );
+       }
+    else
+       {
+       /* Yes.  We'll combine headers and file into a single writev(),
+       ** hoping that this generates a single packet.
+       */
+       struct iovec iv[2];
+
+       iv[0].iov_base = hc->response;
+       iv[0].iov_len = hc->responselen;
+       iv[1].iov_base = &(hc->file_address[c->next_byte_index]);
+       iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes );
+       sz = writev( hc->conn_fd, iv, 2 );
+       }
+
+    if ( sz < 0 && errno == EINTR )
+       return;
+
+    if ( sz == 0 ||
+        ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) )
+       {
+       /* This shouldn't happen, but some kernels, e.g.
+       ** SunOS 4.1.x, are broken and select() says that
+       ** O_NDELAY sockets are always writable even when
+       ** they're actually not.
+       **
+       ** Current workaround is to block sending on this
+       ** socket for a brief adaptively-tuned period.
+       ** Fortunately we already have all the necessary
+       ** blocking code, for use with throttling.
+       */
+       c->wouldblock_delay += MIN_WOULDBLOCK_DELAY;
+       c->conn_state = CNST_PAUSING;
+       fdwatch_del_fd( hc->conn_fd );
+       client_data.p = c;
+       if ( c->wakeup_timer != (Timer*) 0 )
+           syslog( LOG_ERR, "replacing non-null wakeup_timer!" );
+       c->wakeup_timer = tmr_create(
+           tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 );
+       if ( c->wakeup_timer == (Timer*) 0 )
+           {
+           syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" );
+           exit( 1 );
+           }
+       return;
+       }
+
+    if ( sz < 0 )
+       {
+       /* Something went wrong, close this connection.
+       **
+       ** If it's just an EPIPE, don't bother logging, that
+       ** just means the client hung up on us.
+       **
+       ** On some systems, write() occasionally gives an EINVAL.
+       ** Dunno why, something to do with the socket going
+       ** bad.  Anyway, we don't log those either.
+       **
+       ** And ECONNRESET isn't interesting either.
+       */
+       if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET )
+           syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl );
+       clear_connection( c, tvP );
+       return;
+       }
+
+    /* Ok, we wrote something. */
+    c->active_at = tvP->tv_sec;
+    /* Was this a headers + file writev()? */
+    if ( hc->responselen > 0 )
+       {
+       /* Yes; did we write only part of the headers? */
+       if ( sz < hc->responselen )
+           {
+           /* Yes; move the unwritten part to the front of the buffer. */
+           int newlen = hc->responselen - sz;
+           (void) memmove( hc->response, &(hc->response[sz]), newlen );
+           hc->responselen = newlen;
+           sz = 0;
+           }
+       else
+           {
+           /* Nope, we wrote the full headers, so adjust accordingly. */
+           sz -= hc->responselen;
+           hc->responselen = 0;
+           }
+       }
+    /* And update how much of the file we wrote. */
+    c->next_byte_index += sz;
+    c->hc->bytes_sent += sz;
+    for ( tind = 0; tind < c->numtnums; ++tind )
+       throttles[c->tnums[tind]].bytes_since_avg += sz;
+
+    /* Are we done? */
+    if ( c->next_byte_index >= c->end_byte_index )
+       {
+       /* This connection is finished! */
+       finish_connection( c, tvP );
+       return;
+       }
+
+    /* Tune the (blockheaded) wouldblock delay. */
+    if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY )
+       c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY;
+
+    /* If we're throttling, check if we're sending too fast. */
+    if ( c->max_limit != THROTTLE_NOLIMIT )
+       {
+       elapsed = tvP->tv_sec - c->started_at;
+       if ( elapsed == 0 )
+           elapsed = 1;        /* count at least one second */
+       if ( c->hc->bytes_sent / elapsed > c->max_limit )
+           {
+           c->conn_state = CNST_PAUSING;
+           fdwatch_del_fd( hc->conn_fd );
+           /* How long should we wait to get back on schedule?  If less
+           ** than a second (integer math rounding), use 1/2 second.
+           */
+           coast = c->hc->bytes_sent / c->max_limit - elapsed;
+           client_data.p = c;
+           if ( c->wakeup_timer != (Timer*) 0 )
+               syslog( LOG_ERR, "replacing non-null wakeup_timer!" );
+           c->wakeup_timer = tmr_create(
+               tvP, wakeup_connection, client_data,
+               coast > 0 ? ( coast * 1000L ) : 500L, 0 );
+           if ( c->wakeup_timer == (Timer*) 0 )
+               {
+               syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" );
+               exit( 1 );
+               }
+           }
+       }
+    /* (No check on min_limit here, that only controls connection startups.) */
+    }
+
+
+static void
+handle_linger( connecttab* c, struct timeval* tvP )
+    {
+    char buf[4096];
+    int r;
+
+    /* In lingering-close mode we just read and ignore bytes.  An error
+    ** or EOF ends things, otherwise we go until a timeout.
+    */
+    r = read( c->hc->conn_fd, buf, sizeof(buf) );
+    if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
+       return;
+    if ( r <= 0 )
+       really_clear_connection( c, tvP );
+    }
+
+
+static int
+check_throttles( connecttab* c )
+    {
+    int tnum;
+    long l;
+
+    c->numtnums = 0;
+    c->max_limit = c->min_limit = THROTTLE_NOLIMIT;
+    for ( tnum = 0; tnum < numthrottles && c->numtnums < MAXTHROTTLENUMS;
+         ++tnum )
+       if ( match( throttles[tnum].pattern, c->hc->expnfilename ) )
+           {
+           /* If we're way over the limit, don't even start. */
+           if ( throttles[tnum].rate > throttles[tnum].max_limit * 2 )
+               return 0;
+           /* Also don't start if we're under the minimum. */
+           if ( throttles[tnum].rate < throttles[tnum].min_limit )
+               return 0;
+           if ( throttles[tnum].num_sending < 0 )
+               {
+               syslog( LOG_ERR, "throttle sending count was negative - shouldn't happen!" );
+               throttles[tnum].num_sending = 0;
+               }
+           c->tnums[c->numtnums++] = tnum;
+           ++throttles[tnum].num_sending;
+           l = throttles[tnum].max_limit / throttles[tnum].num_sending;
+           if ( c->max_limit == THROTTLE_NOLIMIT )
+               c->max_limit = l;
+           else
+               c->max_limit = MIN( c->max_limit, l );
+           l = throttles[tnum].min_limit;
+           if ( c->min_limit == THROTTLE_NOLIMIT )
+               c->min_limit = l;
+           else
+               c->min_limit = MAX( c->min_limit, l );
+           }
+    return 1;
+    }
+
+
+static void
+clear_throttles( connecttab* c, struct timeval* tvP )
+    {
+    int tind;
+
+    for ( tind = 0; tind < c->numtnums; ++tind )
+       --throttles[c->tnums[tind]].num_sending;
+    }
+
+
+static void
+update_throttles( ClientData client_data, struct timeval* nowP )
+    {
+    int tnum, tind;
+    int cnum;
+    connecttab* c;
+    long l;
+
+    /* Update the average sending rate for each throttle.  This is only used
+    ** when new connections start up.
+    */
+    for ( tnum = 0; tnum < numthrottles; ++tnum )
+       {
+       throttles[tnum].rate = ( 2 * throttles[tnum].rate + throttles[tnum].bytes_since_avg / THROTTLE_TIME ) / 3;
+       throttles[tnum].bytes_since_avg = 0;
+       /* Log a warning message if necessary. */
+       if ( throttles[tnum].rate > throttles[tnum].max_limit && throttles[tnum].num_sending != 0 )
+           {
+           if ( throttles[tnum].rate > throttles[tnum].max_limit * 2 )
+               syslog( LOG_NOTICE, "throttle #%d '%.80s' rate %ld greatly exceeding limit %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].max_limit, throttles[tnum].num_sending );
+           else
+               syslog( LOG_INFO, "throttle #%d '%.80s' rate %ld exceeding limit %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].max_limit, throttles[tnum].num_sending );
+           }
+       if ( throttles[tnum].rate < throttles[tnum].min_limit && throttles[tnum].num_sending != 0 )
+           {
+           syslog( LOG_NOTICE, "throttle #%d '%.80s' rate %ld lower than minimum %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].min_limit, throttles[tnum].num_sending );
+           }
+       }
+
+    /* Now update the sending rate on all the currently-sending connections,
+    ** redistributing it evenly.
+    */
+    for ( cnum = 0; cnum < max_connects; ++cnum )
+       {
+       c = &connects[cnum];
+       if ( c->conn_state == CNST_SENDING || c->conn_state == CNST_PAUSING )
+           {
+           c->max_limit = THROTTLE_NOLIMIT;
+           for ( tind = 0; tind < c->numtnums; ++tind )
+               {
+               tnum = c->tnums[tind];
+               l = throttles[tnum].max_limit / throttles[tnum].num_sending;
+               if ( c->max_limit == THROTTLE_NOLIMIT )
+                   c->max_limit = l;
+               else
+                   c->max_limit = MIN( c->max_limit, l );
+               }
+           }
+       }
+    }
+
+
+static void
+finish_connection( connecttab* c, struct timeval* tvP )
+    {
+    /* If we haven't actually sent the buffered response yet, do so now. */
+    httpd_write_response( c->hc );
+
+    /* And clear. */
+    clear_connection( c, tvP );
+    }
+
+
+static void
+clear_connection( connecttab* c, struct timeval* tvP )
+    {
+    ClientData client_data;
+
+    if ( c->wakeup_timer != (Timer*) 0 )
+       {
+       tmr_cancel( c->wakeup_timer );
+       c->wakeup_timer = 0;
+       }
+
+    /* This is our version of Apache's lingering_close() routine, which is
+    ** their version of the often-broken SO_LINGER socket option.  For why
+    ** this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html
+    ** What we do is delay the actual closing for a few seconds, while reading
+    ** any bytes that come over the connection.  However, we don't want to do
+    ** this unless it's necessary, because it ties up a connection slot and
+    ** file descriptor which means our maximum connection-handling rate
+    ** is lower.  So, elsewhere we set a flag when we detect the few
+    ** circumstances that make a lingering close necessary.  If the flag
+    ** isn't set we do the real close now.
+    */
+    if ( c->conn_state == CNST_LINGERING )
+       {
+       /* If we were already lingering, shut down for real. */
+       tmr_cancel( c->linger_timer );
+       c->linger_timer = (Timer*) 0;
+       c->hc->should_linger = 0;
+       }
+    if ( c->hc->should_linger )
+       {
+       if ( c->conn_state != CNST_PAUSING )
+           fdwatch_del_fd( c->hc->conn_fd );
+       c->conn_state = CNST_LINGERING;
+       shutdown( c->hc->conn_fd, SHUT_WR );
+       fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
+       client_data.p = c;
+       if ( c->linger_timer != (Timer*) 0 )
+           syslog( LOG_ERR, "replacing non-null linger_timer!" );
+       c->linger_timer = tmr_create(
+           tvP, linger_clear_connection, client_data, LINGER_TIME, 0 );
+       if ( c->linger_timer == (Timer*) 0 )
+           {
+           syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" );
+           exit( 1 );
+           }
+       }
+    else
+       really_clear_connection( c, tvP );
+    }
+
+
+static void
+really_clear_connection( connecttab* c, struct timeval* tvP )
+    {
+    stats_bytes += c->hc->bytes_sent;
+    if ( c->conn_state != CNST_PAUSING )
+       fdwatch_del_fd( c->hc->conn_fd );
+    httpd_close_conn( c->hc, tvP );
+    clear_throttles( c, tvP );
+    if ( c->linger_timer != (Timer*) 0 )
+       {
+       tmr_cancel( c->linger_timer );
+       c->linger_timer = 0;
+       }
+    c->conn_state = CNST_FREE;
+    c->next_free_connect = first_free_connect;
+    first_free_connect = c - connects; /* division by sizeof is implied */
+    --num_connects;
+    }
+
+
+static void
+idle( ClientData client_data, struct timeval* nowP )
+    {
+    int cnum;
+    connecttab* c;
+
+    for ( cnum = 0; cnum < max_connects; ++cnum )
+       {
+       c = &connects[cnum];
+       switch ( c->conn_state )
+           {
+           case CNST_READING:
+           if ( nowP->tv_sec - c->active_at >= IDLE_READ_TIMELIMIT )
+               {
+               syslog( LOG_INFO,
+                   "%.80s connection timed out reading",
+                   httpd_ntoa( &c->hc->client_addr ) );
+               httpd_send_err(
+                   c->hc, 408, httpd_err408title, "", httpd_err408form, "" );
+               finish_connection( c, nowP );
+               }
+           break;
+           case CNST_SENDING:
+           case CNST_PAUSING:
+           if ( nowP->tv_sec - c->active_at >= IDLE_SEND_TIMELIMIT )
+               {
+               syslog( LOG_INFO,
+                   "%.80s connection timed out sending",
+                   httpd_ntoa( &c->hc->client_addr ) );
+               clear_connection( c, nowP );
+               }
+           break;
+           }
+       }
+    }
+
+
+static void
+wakeup_connection( ClientData client_data, struct timeval* nowP )
+    {
+    connecttab* c;
+
+    c = (connecttab*) client_data.p;
+    c->wakeup_timer = (Timer*) 0;
+    if ( c->conn_state == CNST_PAUSING )
+       {
+       c->conn_state = CNST_SENDING;
+       fdwatch_add_fd( c->hc->conn_fd, c, FDW_WRITE );
+       }
+    }
+
+static void
+linger_clear_connection( ClientData client_data, struct timeval* nowP )
+    {
+    connecttab* c;
+
+    c = (connecttab*) client_data.p;
+    c->linger_timer = (Timer*) 0;
+    really_clear_connection( c, nowP );
+    }
+
+
+static void
+occasional( ClientData client_data, struct timeval* nowP )
+    {
+    mmc_cleanup( nowP );
+    tmr_cleanup();
+    watchdog_flag = 1;         /* let the watchdog know that we are alive */
+    }
+
+
+#ifdef STATS_TIME
+static void
+show_stats( ClientData client_data, struct timeval* nowP )
+    {
+    logstats( nowP );
+    }
+#endif /* STATS_TIME */
+
+
+/* Generate debugging statistics syslog messages for all packages. */
+static void
+logstats( struct timeval* nowP )
+    {
+    struct timeval tv;
+    time_t now;
+    long up_secs, stats_secs;
+
+    if ( nowP == (struct timeval*) 0 )
+       {
+       (void) gettimeofday( &tv, (struct timezone*) 0 );
+       nowP = &tv;
+       }
+    now = nowP->tv_sec;
+    up_secs = now - start_time;
+    stats_secs = now - stats_time;
+    if ( stats_secs == 0 )
+       stats_secs = 1; /* fudge */
+    stats_time = now;
+    syslog( LOG_NOTICE,
+       "up %ld seconds, stats for %ld seconds:", up_secs, stats_secs );
+
+    thttpd_logstats( stats_secs );
+    httpd_logstats( stats_secs );
+    mmc_logstats( stats_secs );
+    fdwatch_logstats( stats_secs );
+    tmr_logstats( stats_secs );
+    }
+
+
+/* Generate debugging statistics syslog message. */
+static void
+thttpd_logstats( long secs )
+    {
+    if ( secs > 0 )
+       syslog( LOG_NOTICE,
+           "  thttpd - %ld connections (%g/sec), %d max simultaneous, %lld bytes (%g/sec), %d httpd_conns allocated",
+           stats_connections, (float) stats_connections / secs,
+           stats_simultaneous, (long long) stats_bytes,
+           (float) stats_bytes / secs, httpd_conn_count );
+    stats_connections = 0;
+    stats_bytes = 0;
+    stats_simultaneous = 0;
+    }
diff --git a/thttpd.o b/thttpd.o
new file mode 100644 (file)
index 0000000..8176a6e
Binary files /dev/null and b/thttpd.o differ
diff --git a/timers.c b/timers.c
new file mode 100644 (file)
index 0000000..908304a
--- /dev/null
+++ b/timers.c
@@ -0,0 +1,351 @@
+/* timers.c - simple timer routines
+**
+** Copyright © 1995,1998,2000,2014 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "timers.h"
+
+
+#define HASH_SIZE 67
+static Timer* timers[HASH_SIZE];
+static Timer* free_timers;
+static int alloc_count, active_count, free_count;
+
+ClientData JunkClientData;
+
+
+
+static unsigned int
+hash( Timer* t )
+    {
+    /* We can hash on the trigger time, even though it can change over
+    ** the life of a timer via either the periodic bit or the tmr_reset()
+    ** call.  This is because both of those guys call l_resort(), which
+    ** recomputes the hash and moves the timer to the appropriate list.
+    */
+    return (
+       (unsigned int) t->time.tv_sec ^
+       (unsigned int) t->time.tv_usec ) % HASH_SIZE;
+    }
+
+
+static void
+l_add( Timer* t )
+    {
+    int h = t->hash;
+    Timer* t2;
+    Timer* t2prev;
+
+    t2 = timers[h];
+    if ( t2 == (Timer*) 0 )
+       {
+       /* The list is empty. */
+       timers[h] = t;
+       t->prev = t->next = (Timer*) 0;
+       }
+    else
+       {
+       if ( t->time.tv_sec < t2->time.tv_sec ||
+            ( t->time.tv_sec == t2->time.tv_sec &&
+              t->time.tv_usec <= t2->time.tv_usec ) )
+           {
+           /* The new timer goes at the head of the list. */
+           timers[h] = t;
+           t->prev = (Timer*) 0;
+           t->next = t2;
+           t2->prev = t;
+           }
+       else
+           {
+           /* Walk the list to find the insertion point. */
+           for ( t2prev = t2, t2 = t2->next; t2 != (Timer*) 0;
+                 t2prev = t2, t2 = t2->next )
+               {
+               if ( t->time.tv_sec < t2->time.tv_sec ||
+                    ( t->time.tv_sec == t2->time.tv_sec &&
+                      t->time.tv_usec <= t2->time.tv_usec ) )
+                   {
+                   /* Found it. */
+                   t2prev->next = t;
+                   t->prev = t2prev;
+                   t->next = t2;
+                   t2->prev = t;
+                   return;
+                   }
+               }
+           /* Oops, got to the end of the list.  Add to tail. */
+           t2prev->next = t;
+           t->prev = t2prev;
+           t->next = (Timer*) 0;
+           }
+       }
+    }
+
+
+static void
+l_remove( Timer* t )
+    {
+    int h = t->hash;
+
+    if ( t->prev == (Timer*) 0 )
+       timers[h] = t->next;
+    else
+       t->prev->next = t->next;
+    if ( t->next != (Timer*) 0 )
+       t->next->prev = t->prev;
+    }
+
+
+static void
+l_resort( Timer* t )
+    {
+    /* Remove the timer from its old list. */
+    l_remove( t );
+    /* Recompute the hash. */
+    t->hash = hash( t );
+    /* And add it back in to its new list, sorted correctly. */
+    l_add( t );
+    }
+
+
+void
+tmr_init( void )
+    {
+    int h;
+
+    for ( h = 0; h < HASH_SIZE; ++h )
+       timers[h] = (Timer*) 0;
+    free_timers = (Timer*) 0;
+    alloc_count = active_count = free_count = 0;
+    }
+
+
+Timer*
+tmr_create(
+    struct timeval* nowP, TimerProc* timer_proc, ClientData client_data,
+    long msecs, int periodic )
+    {
+    Timer* t;
+
+    if ( free_timers != (Timer*) 0 )
+       {
+       t = free_timers;
+       free_timers = t->next;
+       --free_count;
+       }
+    else
+       {
+       t = (Timer*) malloc( sizeof(Timer) );
+       if ( t == (Timer*) 0 )
+           return (Timer*) 0;
+       ++alloc_count;
+       }
+
+    t->timer_proc = timer_proc;
+    t->client_data = client_data;
+    t->msecs = msecs;
+    t->periodic = periodic;
+    if ( nowP != (struct timeval*) 0 )
+       t->time = *nowP;
+    else
+       (void) gettimeofday( &t->time, (struct timezone*) 0 );
+    t->time.tv_sec += msecs / 1000L;
+    t->time.tv_usec += ( msecs % 1000L ) * 1000L;
+    if ( t->time.tv_usec >= 1000000L )
+       {
+       t->time.tv_sec += t->time.tv_usec / 1000000L;
+       t->time.tv_usec %= 1000000L;
+       }
+    t->hash = hash( t );
+    /* Add the new timer to the proper active list. */
+    l_add( t );
+    ++active_count;
+
+    return t;
+    }
+
+
+struct timeval*
+tmr_timeout( struct timeval* nowP )
+    {
+    long msecs;
+    static struct timeval timeout;
+
+    msecs = tmr_mstimeout( nowP );
+    if ( msecs == INFTIM )
+       return (struct timeval*) 0;
+    timeout.tv_sec = msecs / 1000L;
+    timeout.tv_usec = ( msecs % 1000L ) * 1000L;
+    return &timeout;
+    }
+
+
+long
+tmr_mstimeout( struct timeval* nowP )
+    {
+    int h;
+    int gotone;
+    long msecs, m;
+    Timer* t;
+
+    gotone = 0;
+    msecs = 0;          /* make lint happy */
+    /* Since the lists are sorted, we only need to look at the
+    ** first timer on each one.
+    */
+    for ( h = 0; h < HASH_SIZE; ++h )
+       {
+       t = timers[h];
+       if ( t != (Timer*) 0 )
+           {
+           m = ( t->time.tv_sec - nowP->tv_sec ) * 1000L +
+               ( t->time.tv_usec - nowP->tv_usec ) / 1000L;
+           if ( ! gotone )
+               {
+               msecs = m;
+               gotone = 1;
+               }
+           else if ( m < msecs )
+               msecs = m;
+           }
+       }
+    if ( ! gotone )
+       return INFTIM;
+    if ( msecs <= 0 )
+       msecs = 0;
+    return msecs;
+    }
+
+
+void
+tmr_run( struct timeval* nowP )
+    {
+    int h;
+    Timer* t;
+    Timer* next;
+
+    for ( h = 0; h < HASH_SIZE; ++h )
+       for ( t = timers[h]; t != (Timer*) 0; t = next )
+           {
+           next = t->next;
+           /* Since the lists are sorted, as soon as we find a timer
+           ** that isn't ready yet, we can go on to the next list.
+           */
+           if ( t->time.tv_sec > nowP->tv_sec ||
+                ( t->time.tv_sec == nowP->tv_sec &&
+                  t->time.tv_usec > nowP->tv_usec ) )
+               break;
+           (t->timer_proc)( t->client_data, nowP );
+           if ( t->periodic )
+               {
+               /* Reschedule. */
+               t->time.tv_sec += t->msecs / 1000L;
+               t->time.tv_usec += ( t->msecs % 1000L ) * 1000L;
+               if ( t->time.tv_usec >= 1000000L )
+                   {
+                   t->time.tv_sec += t->time.tv_usec / 1000000L;
+                   t->time.tv_usec %= 1000000L;
+                   }
+               l_resort( t );
+               }
+           else
+               tmr_cancel( t );
+           }
+    }
+
+
+void
+tmr_reset( struct timeval* nowP, Timer* t )
+    {
+    t->time = *nowP;
+    t->time.tv_sec += t->msecs / 1000L;
+    t->time.tv_usec += ( t->msecs % 1000L ) * 1000L;
+    if ( t->time.tv_usec >= 1000000L )
+       {
+       t->time.tv_sec += t->time.tv_usec / 1000000L;
+       t->time.tv_usec %= 1000000L;
+       }
+    l_resort( t );
+    }
+
+
+void
+tmr_cancel( Timer* t )
+    {
+    /* Remove it from its active list. */
+    l_remove( t );
+    --active_count;
+    /* And put it on the free list. */
+    t->next = free_timers;
+    free_timers = t;
+    ++free_count;
+    t->prev = (Timer*) 0;
+    }
+
+
+void
+tmr_cleanup( void )
+    {
+    Timer* t;
+
+    while ( free_timers != (Timer*) 0 )
+       {
+       t = free_timers;
+       free_timers = t->next;
+       --free_count;
+       free( (void*) t );
+       --alloc_count;
+       }
+    }
+
+
+void
+tmr_term( void )
+    {
+    int h;
+
+    for ( h = 0; h < HASH_SIZE; ++h )
+       while ( timers[h] != (Timer*) 0 )
+           tmr_cancel( timers[h] );
+    tmr_cleanup();
+    }
+
+
+/* Generate debugging statistics syslog message. */
+void
+tmr_logstats( long secs )
+    {
+    syslog(
+       LOG_NOTICE, "  timers - %d allocated, %d active, %d free",
+       alloc_count, active_count, free_count );
+    if ( active_count + free_count != alloc_count )
+       syslog( LOG_ERR, "timer counts don't add up!" );
+    }
diff --git a/timers.h b/timers.h
new file mode 100644 (file)
index 0000000..aaa06c6
--- /dev/null
+++ b/timers.h
@@ -0,0 +1,109 @@
+/* timers.h - header file for timers package
+**
+** Copyright © 1995,1998,1999,2000,2014 by Jef Poskanzer <jef@mail.acme.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+#ifndef _TIMERS_H_
+#define _TIMERS_H_
+
+#include <sys/time.h>
+
+#ifndef INFTIM
+#define INFTIM -1
+#endif /* INFTIM */
+
+/* ClientData is a random value that tags along with a timer.  The client
+** can use it for whatever, and it gets passed to the callback when the
+** timer triggers.
+*/
+typedef union {
+    void* p;
+    int i;
+    long l;
+    } ClientData;
+
+extern ClientData JunkClientData;      /* for use when you don't care */
+
+/* The TimerProc gets called when the timer expires.  It gets passed
+** the ClientData associated with the timer, and a timeval in case
+** it wants to schedule another timer.
+*/
+typedef void TimerProc( ClientData client_data, struct timeval* nowP );
+
+/* The Timer struct. */
+typedef struct TimerStruct {
+    TimerProc* timer_proc;
+    ClientData client_data;
+    long msecs;
+    int periodic;
+    struct timeval time;
+    struct TimerStruct* prev;
+    struct TimerStruct* next;
+    int hash;
+    } Timer;
+
+/* Initialize the timer package. */
+void tmr_init( void );
+
+/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */
+Timer* tmr_create(
+    struct timeval* nowP, TimerProc* timer_proc, ClientData client_data,
+    long msecs, int periodic );
+
+/* Returns a timeout indicating how long until the next timer triggers.  You
+** can just put the call to this routine right in your select().  Returns
+** (struct timeval*) 0 if no timers are pending.
+*/
+struct timeval* tmr_timeout( struct timeval* nowP );
+
+/* Returns a timeout in milliseconds indicating how long until the next timer
+** triggers.  You can just put the call to this routine right in your poll().
+** Returns INFTIM (-1) if no timers are pending.
+*/
+long tmr_mstimeout( struct timeval* nowP );
+
+/* Run the list of timers. Your main program needs to call this every so often,
+** or as indicated by tmr_timeout().
+*/
+void tmr_run( struct timeval* nowP );
+
+/* Reset the clock on a timer, to current time plus the original timeout. */
+void tmr_reset( struct timeval* nowP, Timer* timer );
+
+/* Deschedule a timer.  Note that non-periodic timers are automatically
+** descheduled when they run, so you don't have to call this on them.
+*/
+void tmr_cancel( Timer* timer );
+
+/* Clean up the timers package, freeing any unused storage. */
+void tmr_cleanup( void );
+
+/* Cancel all timers and free storage, usually in preparation for exiting. */
+void tmr_term( void );
+
+/* Generate debugging statistics syslog message. */
+void tmr_logstats( long secs );
+
+#endif /* _TIMERS_H_ */
diff --git a/timers.o b/timers.o
new file mode 100644 (file)
index 0000000..f7ae5ee
Binary files /dev/null and b/timers.o differ
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..8d841b9
--- /dev/null
+++ b/version.h
@@ -0,0 +1,9 @@
+/* version.h - version defines for thttpd and libhttpd */
+
+#ifndef _VERSION_H_
+#define _VERSION_H_
+
+#define SERVER_SOFTWARE "thttpd/2.29 23May2018"
+#define SERVER_ADDRESS "http://www.acme.com/software/thttpd/"
+
+#endif /* _VERSION_H_ */