Import from upstream 2.29

This commit is contained in:
Cassowary 2023-04-27 12:44:23 -07:00
commit eb3efcc450
51 changed files with 18219 additions and 0 deletions

51
FILES Normal file
View File

@ -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

40
INSTALL Normal file
View File

@ -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.

173
Makefile.in Normal file
View File

@ -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

31
README Normal file
View File

@ -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/

80
TODO Normal file
View File

@ -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

188
aclocal.m4 vendored Normal file
View File

@ -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])

29
cgi-bin/printenv Executable file
View File

@ -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

86
cgi-src/Makefile.in Normal file
View File

@ -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

69
cgi-src/phf.c Normal file
View File

@ -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 );
}

79
cgi-src/redirect.8 Normal file
View File

@ -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.

215
cgi-src/redirect.c Normal file
View File

@ -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 );
}

142
cgi-src/ssi.8 Normal file
View File

@ -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.

763
cgi-src/ssi.c Normal file
View File

@ -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 );
}

693
config.guess vendored Executable file
View File

@ -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

392
config.h Normal file
View File

@ -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_ */

927
config.sub vendored Executable file
View File

@ -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

2782
configure vendored Executable file

File diff suppressed because it is too large Load Diff

138
configure.in Normal file
View File

@ -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)

View File

@ -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

47
contrib/redhat-rpm/thttpd.init Executable file
View File

@ -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 ''

View File

@ -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

86
extras/Makefile.in Normal file
View File

@ -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

16
extras/htpasswd.1 Normal file
View File

@ -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.

218
extras/htpasswd.c Normal file
View File

@ -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);
}

34
extras/makeweb.1 Normal file
View File

@ -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.

256
extras/makeweb.c Normal file
View File

@ -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 );
}

68
extras/syslogtocern Executable file
View File

@ -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

45
extras/syslogtocern.8 Normal file
View File

@ -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.

834
fdwatch.c Normal file
View File

@ -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 */

85
fdwatch.h Normal file
View File

@ -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_ */

14
index.html Normal file
View File

@ -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>

250
install-sh Executable file
View File

@ -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

4279
libhttpd.c Normal file

File diff suppressed because it is too large Load Diff

291
libhttpd.h Normal file
View File

@ -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_ */

88
match.c Normal file
View File

@ -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;
}

36
match.h Normal file
View File

@ -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_ */

8
mime_encodings.txt Normal file
View File

@ -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

198
mime_types.txt Normal file
View File

@ -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

531
mmc.c Normal file
View File

@ -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!" );
}

55
mmc.h Normal file
View File

@ -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_ */

19
scripts/500.thttpd-rotate Executable file
View File

@ -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

47
scripts/thttpd.sh Executable file
View File

@ -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"

23
scripts/thttpd_wrapper Executable file
View File

@ -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
) &

38
strerror.c Normal file
View File

@ -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);
}

328
tdate_parse.c Normal file
View File

@ -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;
}

33
tdate_parse.h Normal file
View File

@ -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_ */

596
thttpd.8 Normal file
View File

@ -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.

2181
thttpd.c Normal file

File diff suppressed because it is too large Load Diff

351
timers.c Normal file
View File

@ -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!" );
}

109
timers.h Normal file
View File

@ -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_ */

9
version.h Normal file
View File

@ -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_ */