From 185646b54a971bc038bbbec02163f3e755a3f79a Mon Sep 17 00:00:00 2001 From: girst Date: Sat, 25 Mar 2017 14:53:09 +0100 Subject: [PATCH] initial code import --- ORFText.cgi | 17 + README | 39 + channels.conf | 4 + html.pl | 87 + install.sh | 15 + plain.pl | 93 + serv.sh | 13 + src/dvbtext-src/Makefile | 24 + src/dvbtext-src/README | 99 + src/dvbtext-src/dvbtext.c | 301 ++ src/dvbtext-src/dvbtext.c-original-ish | 300 ++ src/dvbtext-src/tables.h | 80 + src/freqlist.conf | 3 + src/thttpd-2.27/FILES | 51 + src/thttpd-2.27/INSTALL | 40 + src/thttpd-2.27/Makefile | 174 + src/thttpd-2.27/Makefile.in | 173 + src/thttpd-2.27/README | 31 + src/thttpd-2.27/TODO | 80 + src/thttpd-2.27/aclocal.m4 | 188 + src/thttpd-2.27/cgi-bin/printenv | 29 + src/thttpd-2.27/cgi-src/Makefile | 87 + src/thttpd-2.27/cgi-src/Makefile.in | 86 + src/thttpd-2.27/cgi-src/phf.c | 69 + src/thttpd-2.27/cgi-src/redirect.8 | 79 + src/thttpd-2.27/cgi-src/redirect.c | 215 + src/thttpd-2.27/cgi-src/ssi.8 | 142 + src/thttpd-2.27/cgi-src/ssi.c | 763 +++ src/thttpd-2.27/config.cache | 63 + src/thttpd-2.27/config.guess | 693 +++ src/thttpd-2.27/config.h | 392 ++ src/thttpd-2.27/config.log | 300 ++ src/thttpd-2.27/config.status | 180 + src/thttpd-2.27/config.sub | 927 ++++ src/thttpd-2.27/configure | 2782 +++++++++++ src/thttpd-2.27/configure.in | 138 + .../contrib/redhat-rpm/thttpd.conf | 14 + .../contrib/redhat-rpm/thttpd.init | 47 + .../contrib/redhat-rpm/thttpd.spec | 154 + src/thttpd-2.27/extras/Makefile | 87 + src/thttpd-2.27/extras/Makefile.in | 86 + src/thttpd-2.27/extras/htpasswd.1 | 16 + src/thttpd-2.27/extras/htpasswd.c | 217 + src/thttpd-2.27/extras/makeweb.1 | 34 + src/thttpd-2.27/extras/makeweb.c | 256 + src/thttpd-2.27/extras/syslogtocern | 68 + src/thttpd-2.27/extras/syslogtocern.8 | 45 + src/thttpd-2.27/fdwatch.c | 834 ++++ src/thttpd-2.27/fdwatch.h | 85 + src/thttpd-2.27/index.html | 14 + src/thttpd-2.27/install-sh | 250 + src/thttpd-2.27/libhttpd.c | 4280 +++++++++++++++++ src/thttpd-2.27/libhttpd.h | 288 ++ src/thttpd-2.27/match.c | 88 + src/thttpd-2.27/match.h | 36 + src/thttpd-2.27/mime_encodings.txt | 8 + src/thttpd-2.27/mime_types.txt | 198 + src/thttpd-2.27/mmc.c | 531 ++ src/thttpd-2.27/mmc.h | 55 + src/thttpd-2.27/scripts/500.thttpd-rotate | 19 + src/thttpd-2.27/scripts/thttpd.sh | 48 + src/thttpd-2.27/scripts/thttpd_wrapper | 23 + src/thttpd-2.27/strerror.c | 38 + src/thttpd-2.27/tdate_parse.c | 328 ++ src/thttpd-2.27/tdate_parse.h | 33 + src/thttpd-2.27/thttpd.8 | 596 +++ src/thttpd-2.27/thttpd.c | 2181 +++++++++ src/thttpd-2.27/timers.c | 351 ++ src/thttpd-2.27/timers.h | 109 + src/thttpd-2.27/version.h | 9 + src/vtx2ascii-src/Makefile | 17 + src/vtx2ascii-src/README | 24 + src/vtx2ascii-src/cct.h | 38 + src/vtx2ascii-src/fileio.c | 163 + src/vtx2ascii-src/fileio.h | 47 + src/vtx2ascii-src/main.c | 160 + src/vtx2ascii-src/misc.h | 41 + src/vtx2ascii-src/sys/vtx.h | 151 + src/vtx2ascii-src/vtx.cgi | 140 + src/vtx2ascii-src/vtx_assert.h | 46 + src/vtx2ascii-src/vtxdecode.c | 210 + src/vtx2ascii-src/vtxdecode.h | 45 + src/vtx2ascii-src/vtxtools.c | 140 + src/vtx2ascii-src/vtxtools.h | 23 + ttxd.service | 12 + 85 files changed, 21440 insertions(+) create mode 100755 ORFText.cgi create mode 100644 README create mode 100644 channels.conf create mode 100755 html.pl create mode 100644 install.sh create mode 100755 plain.pl create mode 100755 serv.sh create mode 100644 src/dvbtext-src/Makefile create mode 100644 src/dvbtext-src/README create mode 100644 src/dvbtext-src/dvbtext.c create mode 100644 src/dvbtext-src/dvbtext.c-original-ish create mode 100644 src/dvbtext-src/tables.h create mode 100644 src/freqlist.conf create mode 100644 src/thttpd-2.27/FILES create mode 100644 src/thttpd-2.27/INSTALL create mode 100644 src/thttpd-2.27/Makefile create mode 100644 src/thttpd-2.27/Makefile.in create mode 100644 src/thttpd-2.27/README create mode 100644 src/thttpd-2.27/TODO create mode 100644 src/thttpd-2.27/aclocal.m4 create mode 100755 src/thttpd-2.27/cgi-bin/printenv create mode 100644 src/thttpd-2.27/cgi-src/Makefile create mode 100644 src/thttpd-2.27/cgi-src/Makefile.in create mode 100644 src/thttpd-2.27/cgi-src/phf.c create mode 100644 src/thttpd-2.27/cgi-src/redirect.8 create mode 100644 src/thttpd-2.27/cgi-src/redirect.c create mode 100644 src/thttpd-2.27/cgi-src/ssi.8 create mode 100644 src/thttpd-2.27/cgi-src/ssi.c create mode 100644 src/thttpd-2.27/config.cache create mode 100755 src/thttpd-2.27/config.guess create mode 100644 src/thttpd-2.27/config.h create mode 100644 src/thttpd-2.27/config.log create mode 100755 src/thttpd-2.27/config.status create mode 100755 src/thttpd-2.27/config.sub create mode 100755 src/thttpd-2.27/configure create mode 100644 src/thttpd-2.27/configure.in create mode 100644 src/thttpd-2.27/contrib/redhat-rpm/thttpd.conf create mode 100755 src/thttpd-2.27/contrib/redhat-rpm/thttpd.init create mode 100644 src/thttpd-2.27/contrib/redhat-rpm/thttpd.spec create mode 100644 src/thttpd-2.27/extras/Makefile create mode 100644 src/thttpd-2.27/extras/Makefile.in create mode 100644 src/thttpd-2.27/extras/htpasswd.1 create mode 100644 src/thttpd-2.27/extras/htpasswd.c create mode 100644 src/thttpd-2.27/extras/makeweb.1 create mode 100644 src/thttpd-2.27/extras/makeweb.c create mode 100755 src/thttpd-2.27/extras/syslogtocern create mode 100644 src/thttpd-2.27/extras/syslogtocern.8 create mode 100644 src/thttpd-2.27/fdwatch.c create mode 100644 src/thttpd-2.27/fdwatch.h create mode 100644 src/thttpd-2.27/index.html create mode 100755 src/thttpd-2.27/install-sh create mode 100644 src/thttpd-2.27/libhttpd.c create mode 100644 src/thttpd-2.27/libhttpd.h create mode 100644 src/thttpd-2.27/match.c create mode 100644 src/thttpd-2.27/match.h create mode 100644 src/thttpd-2.27/mime_encodings.txt create mode 100644 src/thttpd-2.27/mime_types.txt create mode 100644 src/thttpd-2.27/mmc.c create mode 100644 src/thttpd-2.27/mmc.h create mode 100755 src/thttpd-2.27/scripts/500.thttpd-rotate create mode 100755 src/thttpd-2.27/scripts/thttpd.sh create mode 100755 src/thttpd-2.27/scripts/thttpd_wrapper create mode 100644 src/thttpd-2.27/strerror.c create mode 100644 src/thttpd-2.27/tdate_parse.c create mode 100644 src/thttpd-2.27/tdate_parse.h create mode 100644 src/thttpd-2.27/thttpd.8 create mode 100644 src/thttpd-2.27/thttpd.c create mode 100644 src/thttpd-2.27/timers.c create mode 100644 src/thttpd-2.27/timers.h create mode 100644 src/thttpd-2.27/version.h create mode 100644 src/vtx2ascii-src/Makefile create mode 100644 src/vtx2ascii-src/README create mode 100644 src/vtx2ascii-src/cct.h create mode 100644 src/vtx2ascii-src/fileio.c create mode 100644 src/vtx2ascii-src/fileio.h create mode 100644 src/vtx2ascii-src/main.c create mode 100644 src/vtx2ascii-src/misc.h create mode 100644 src/vtx2ascii-src/sys/vtx.h create mode 100755 src/vtx2ascii-src/vtx.cgi create mode 100644 src/vtx2ascii-src/vtx_assert.h create mode 100644 src/vtx2ascii-src/vtxdecode.c create mode 100644 src/vtx2ascii-src/vtxdecode.h create mode 100644 src/vtx2ascii-src/vtxtools.c create mode 100644 src/vtx2ascii-src/vtxtools.h create mode 100644 ttxd.service diff --git a/ORFText.cgi b/ORFText.cgi new file mode 100755 index 0000000..475f9ed --- /dev/null +++ b/ORFText.cgi @@ -0,0 +1,17 @@ +#!/usr/bin/perl -X + +use strict; +use warnings; +use 5.010; + +my @pages = (101, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 133, 134, 102, 136, 137, 138, 139, 140, 141, 142, 143, 108, 461, 462, 463, 464, 465); + +print "Content-type: text/html\n\n"; + +print "ORFText News"; +print "

ORFText News

"; + +foreach (@pages) { + print `./html.pl /run/ttxd/spool/2/${_}_00.vtx` if -e "/run/ttxd/spool/2/${_}_00.vtx"; +} +print ""; diff --git a/README b/README new file mode 100644 index 0000000..834dfb8 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +TELETEXT SERVER +=============== + +Installation +------------ + +1. `./install.sh` as root +2. create `freqlist.conf` (see example in `src/`) +3. `scan -a $ADAPTERNO freqlist.conf > channels.conf` +4. use `ttxd.service` or `serv.sh` to start the service. + +Usage +----- + +1. run `serv.sh` to tune the TV card and start spooling pages +2. generate an HTML file by running `index.pl` + +Caveats +------- + + * The spool directory and DVB adapter number are hardcoded in `dvbtext`; its source is in `./src/dvbtext-src/dvbtext.c`. + * `index.pl`, `html.pl` and `plain.pl` do not support subpages other than 0. + * `serv.sh` does not check if the card has been tuned; it simply waits 5 seconds. + * The spool directory is `/run/ttxd/spool/`, to avoid disk wear. + * The accompaning systemd service is `/etc/systemd/system/ttx.service`, where the names of the processes `dvbtext`, `tzap`, and `thttpd` are hardcoded. + * since `killall thttpd` is used to start and stop the service, rename that executable if you already running an instance of `thttpd` for other web services. + +Notes +----- + +Currently, the service is using `/dev/dvb/adapter0` (PCIe 05:00.0) for ORF via DVB-T. + +Included Software +----------------- + +This package contains software of third parties: + * dvbtext - Dave Chapman, GNU GPL v2+ + * vtx2ascii - Gerd, Martin Buck (No license supplied) + * thttpd - Jef Poskanzer, 2 clause BSD (modified) diff --git a/channels.conf b/channels.conf new file mode 100644 index 0000000..e25e7a9 --- /dev/null +++ b/channels.conf @@ -0,0 +1,4 @@ +ORF1:634000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:6010:6011:10101 +ORF2 K:634000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:6020:6021:10116 +ORF2 T:634000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:6020:6021:10136 +ORF2T HD:634000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:6150:0:10150 diff --git a/html.pl b/html.pl new file mode 100755 index 0000000..7ce82f0 --- /dev/null +++ b/html.pl @@ -0,0 +1,87 @@ +#!/usr/bin/perl -X + +# (C) 2016-2017 Tobias Girstmair +# Extracts hypertext formatted news from ORF Teletext +# uses a modified version of vtx2ascii to decode pages +# from dvbtext's spool directory. + +# Usage: ./plain.pl +# Output: HTML + +use strict; +use warnings; +use 5.010; +binmode STDOUT, ":encoding(utf8)"; + +# Seitenformat: +# 100-109: +# Metadaten: 1 +# Subressort: 2 +# Ressort/Sparte: 3 +# Leer 4 +# Related: 5 +# Leer 6 +# Titel: 7 +# Text: 8-24 +# +# 112-899: +# Metadaten: 1 +# Subressort: 2 +# Ressort/Sparte: 3 +# Leer 4 +# Titel: 5 +# Text: 6-24 +# + +my %meta; +my $title; +my $text = ""; +my $page = shift; +my $subp = 0; #TODO: allow subpages +# run through vtx2ascii (has been modified to output correct ISO 8859-1 without national replacements) +open (VTX, "./vtx2ascii -a $page |") || die ("Can'r run vtx2ascii"); +my $last = ""; +my $is_10x = 0; +do { + # transliterate from ETSI EN 300 706 G0 German to Latin-1 (will be converted to UTF-8 by perl): + tr/[\\]{|}~/\N{U+C4}\N{U+D6}\N{U+DC}\N{U+E4}\N{U+F6}\N{U+FC}\N{U+DF}/; + my $line = $_; + $line =~ s/^\s+|\s+$//g; + chomp ($line); + + given ($.) { + when (1) { %meta = parse_metadata ($line) ; $is_10x = ($meta{'page'}<110) } + when (2) { $meta{'subres'} = $line } + when (3) { $meta{'res'} = $line } + when (4) {} + when (5 + (1*$is_10x)) { $title = $line } + when (4 + (1*$is_10x)) {} + when (4 + (3*$is_10x)) { $title .=$line } + default { $text .= $last . "_EOL_" . ($last eq ""?"":($line eq ""?"
":" ")) } + } + $last = $line unless $. == (5+(2*$is_10x)); +} while (); +$text .= $last; + +#remove hyphenation at original line ending only when in between lowercase letters, replace with soft hyphen to still allow hyphenation when needed. ad _EOL_: linebreaks already stripped in loop above; wouldn't work either way due to single line regex. +$text =~ s/([[:lower:]])-_EOL_ ([[:lower:]])/\1­\2/g; +$text =~ s/_EOL_//g; + +# adblocker: just add more regexes +$text =~ s/Kalendarium - t.glich neu \. 734//g; + +print "

$meta{'page'}: $title
$text

"; + +close (VTX); + +sub parse_metadata { + my @elems = split ' ', @_[0]; + + my %retval = ( + 'page' => shift @elems, + 'channel' => shift @elems, + 'date' => join (' ', @elems) + ); + + return %retval; +} diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..9f4a2f3 --- /dev/null +++ b/install.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [[ $UID -ne 0 ]] +then echo "must be root" + exit 1 +fi + +sh -c 'cd ./src/dvbtext-src/; make' +sh -c 'cd ./src/vtx2ascii-src/; make' +sh -c 'cd ./src/thttpd-2.27/; make' +cp ./src/dvbtext-src/dvbtext . +cp ./src/vtx2ascii-src/vtx2ascii . +cp ./src/thttpd-2.27/thttpd . +cp ./ttxd.service /etc/systemd/system/ +systemctl enable ttxd.service diff --git a/plain.pl b/plain.pl new file mode 100755 index 0000000..a67eed8 --- /dev/null +++ b/plain.pl @@ -0,0 +1,93 @@ +#!/usr/bin/perl -X + +# (C) 2016-2017 Tobias Girstmair +# Extracts plain text news from ORF Teletext +# uses a modified version of vtx2ascii to decode pages +# from dvbtext's spool directory. + +# Usage: ./plain.pl +# Output: Line 1: Heading (pageNo); following lines are news body + +use strict; +use warnings; +use 5.010; +binmode STDOUT, ":encoding(utf8)"; + +# Seitenformat: +# 100-109: +# Metadaten: 1 +# Subressort: 2 +# Ressort/Sparte: 3 +# Leer 4 +# Related: 5 +# Leer 6 +# Titel: 7 +# Text: 8-24 +# +# 112-899: +# Metadaten: 1 +# Subressort: 2 +# Ressort/Sparte: 3 +# Leer 4 +# Titel: 5 +# Text: 6-24 +# + +my %meta; +my $title; +my $text = ""; +# TODO: run tzap/dvbtext in background if not already running +my $page = shift; +my $subp = 0; #shift; #TODO: could be undefined +# run through vtx2ascii (has been modified to output correct ISO 8859-1 without national replacements) +open (VTX, "./vtx2ascii -a $page |") || die ("Can'r run vtx2ascii"); +my $last = ""; +my $is_10x = 0; +do { + # transliterate from ETSI EN 300 706 G0 German to UTF-8: + tr/[\\]{|}~/\N{U+C4}\N{U+D6}\N{U+DC}\N{U+E4}\N{U+F6}\N{U+FC}\N{U+DF}/; + my $line = $_; + $line =~ s/^\s+|\s+$//g; + chomp ($line); + + given ($.) { + when (1) { %meta = parse_metadata ($line) ; $is_10x = ($meta{'page'}<110) } + when (2) { $meta{'subres'} = $line } + when (3) { $meta{'res'} = $line } + when (4) {} + when (5 + (1*$is_10x)) { $title = $line } + when (4 + (1*$is_10x)) {} + when (4 + (3*$is_10x)) { $title .=$line } + default { $text .= $last ."|EOL|". ($last eq ""?"":($line eq ""?"\n":" ")) } + } + $last = $line unless $. == (5+(2*$is_10x)); +} while (); +$text .= $last; + +$text =~ s/([[:lower:]])-\|EOL\| ([[:lower:]])/\1\2/g; #remove hyphenation only when in between lowercase letters +$text =~ s/\|EOL\|//g; #remove hyphenation only when in between lowercase letters + +#ADBlocker +$text =~ s/ORF TELETEXT jetzt auch als App gratis im App-Store für iOS . Android//g; +$text =~ s/Weidenrinde bei R.ckenschmerzen >652 Onlineshop: www\.hafesan\.at//g; + +#DEBUG: +print STDERR "Page: $meta{'page'}\tChannel: $meta{'channel'}\tDate: $meta{'date'}\n"; +print STDERR "Ressort: $meta{'res'}\tSubressort: $meta{'subres'}\n"; +print STDERR "is_10x: ", $is_10x?"yes":"no", "\n"; + +print $title, " ($meta{'page'})\n", $text; + +close (VTX); + +sub parse_metadata { + my @elems = split ' ', @_[0]; + + my %retval = ( + 'page' => shift @elems, + 'channel' => shift @elems, + 'date' => join (' ', @elems) ##date doesnt work TODO + ); + + return %retval; +} diff --git a/serv.sh b/serv.sh new file mode 100755 index 0000000..e11551a --- /dev/null +++ b/serv.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +cd /opt/ttxd/ + +killall tzap dvbtext thttpd + +mkdir -p /run/ttxd/spool/{1,2,3,4,5,6,7,8} + +tzap -a 0 -c channels.conf ORF1 &>/dev/null& +sleep 5 # TODO: detect FE_HAS_LOCK + +./dvbtext 6015 6025 & # 6015=ORF1, 6025=ORF2 +./thttpd -p 8080 -d /opt/ttxd/ -c '**.cgi' diff --git a/src/dvbtext-src/Makefile b/src/dvbtext-src/Makefile new file mode 100644 index 0000000..384c5c9 --- /dev/null +++ b/src/dvbtext-src/Makefile @@ -0,0 +1,24 @@ +INCS= +CFLAGS= -Wall +CC=gcc + +all: dvbtext + +# Delete the following line if you are not using a +# "NEWSTRUCT" driver. If you are using a "NEWSTRUCT" +# driver, it must be later than October 10th 2002 + +NEWSTRUCT=1 + +ifdef NEWSTRUCT + CFLAGS += -DNEWSTRUCT + INCS += -I ../DVB/include +else + INCS += -I ../DVB/ost/include +endif + +dvbtext: dvbtext.c tables.h + $(CC) $(CFLAGS) $(INCS) -o dvbtext dvbtext.c + +clean: + rm -f *.o *~ dvbtext diff --git a/src/dvbtext-src/README b/src/dvbtext-src/README new file mode 100644 index 0000000..fee9dd6 --- /dev/null +++ b/src/dvbtext-src/README @@ -0,0 +1,99 @@ +DVBtext - version 0.1 +--------------------- + +CONTENTS OF THIS FILE: +---------------------- + +1. INSTALLATION +2. USAGE +3. AUTHOR AND CONTACT DETAILS +4. COPYRIGHT NOTICE + + +1. INSTALLATION +--------------- + +1) Modify the root spool directory (VTXDIR) at the start of dvbtext.c + and the path to the DVB/ost/include directory from the driver source. + +2) Compile the application by typing "make". + +3) Create your spool directory and 8 subdirectories numbered "1" to "8" + within that directory. i.e. + + mkdir /video/vtx + cd /video/vtx + mkdir 1 2 3 4 5 6 7 8 + + Obviously, these need to be writable by the user you run dvbtext as. + +4) [Move the dvbtext executable into your path - e.g. /usr/local/bin] + +NOTE: DVBtext uses the DVB driver's "new api". You need to have the +correct devices created under /dev/ost/. If you don't have these, run +the "makedev.napi" script in the DVB/driver directory. + + +2. USAGE +-------- + +1) Tune your DVB card to a channel - e.g. using VDR. +2) Run dvbtext with a list of teletext PIDs for all the channels on the same + transponder as your tuned channel. + +e.g. Tune to ARD (11837h, sr: 27500, vpid: 101, apid:102) on Astra +19E. Then type: + +dvbtext 104 204 304 404 504 604 704 804 + +to spool the teletext pages for ARD, BR3, Hessen-3, ARTE, SR3, WDR, +BR-alpha and SWR BW simultaneously. + +You can then view a page from your console using (for example) the +vtx2ascii program (contained in the oldstuff/vtx directory of the +xawtv source). + +e.g. vtxc2ascii -c /video/vtx/1/100_00.vtx + +Displays a colour (text-only) version on an ANSI capable terminal. + +A channels.conf file for VDR (version 0.71pre2 or above) including +teletext PIDs for many channels on Astra 19 is included with DVBtext. +The teletext PID is the third field from the end - after the video and +audio PIDs. + +NOTE: VDR and DVBtext can happily run together. However, you will +need to stop and restart dvbtext with different parameters when you +change channels. + + +3. AUTHOR AND CONTACT DETAILS +----------------------------- + +DVBtext was written by Dave Chapman . The latest +version is always available from CVS at +http://sourceforge.net/projects/dvbtools/ + +The project home page and released versions of the program can be +found at http://www.linuxstb.org. + +Thanks to Ralph Metzler for developing the DVB driver, the vbidecode +package (on which, DVBtext is based), and for answering my questions. + + +4. COPYRIGHT NOTICE +------------------- + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 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., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/src/dvbtext-src/dvbtext.c b/src/dvbtext-src/dvbtext.c new file mode 100644 index 0000000..15cb1b7 --- /dev/null +++ b/src/dvbtext-src/dvbtext.c @@ -0,0 +1,301 @@ +/* + +dvbtext - a teletext decoder for DVB cards. +(C) Dave Chapman 2001. + +The latest version can be found at http://www.linuxstb.org/dvbtext + +Thanks to: + +Ralph Metzler for his work on both the DVB driver and his old +vbidecode package (some code and ideas in dvbtext are borrowed +from vbidecode). + +Copyright notice: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#ifdef NEWSTRUCT +#include +#else +#include +#endif +#include "tables.h" + +#define VERSION "0.1" +#define VTXDIR "/run/ttxd/spool" +#define ADAPTER "0" +//#define VTXDIR "/opt/TTx_Server/spool" +//#define VTXDIR "/video/vtx" +#define USAGE "\nUSAGE: dvbtext tpid1 tpid2 tpid3 .. tpid8\n\n" + +// There seems to be a limit of 8 teletext streams - OK for most (but +// not all) transponders. +#define MAX_CHANNELS 9 + +typedef struct mag_struct_ { + int valid; + int mag; + unsigned char flags; + unsigned char lang; + int pnum,sub; + unsigned char pagebuf[25*40]; +} mag_struct; + +// FROM vbidecode +// unham 2 bytes into 1, report 2 bit errors but ignore them +unsigned char unham(unsigned char a,unsigned char b) +{ + unsigned char c1,c2; + + c1=unhamtab[a]; + c2=unhamtab[b]; +// if ((c1|c2)&0x40) +// fprintf(stderr,"bad ham!"); + return (c2<<4)|(0x0f&c1); +} + +void write_data(unsigned char* b, int n) { + int i; + + for (i=0;ivalid=1; + memset(mag->pagebuf,' ', 25*40); + mag->pnum=unham(data[0],data[1]); // The lower two (hex) numbers of page + if (mag->pnum==0xff) return; // These are filler lines. Can use to update clock +// fprintf(stderr,"pagenum: %03x\n",c+mag->mag*0x100); + mag->flags=unham(data[2],data[3])&0x80; + mag->flags|=(c&0x40)|((c>>2)&0x20); + c=unham(data[6],data[7]); + mag->flags|=((c<<4)&0x10)|((c<<2)&0x08)|(c&0x04)|((c>>1)&0x02)|((c>>4)&0x01); + mag->lang=((c>>5) & 0x07); + + mag->sub=(unham(data[4],data[5])<<8)|(unham(data[2],data[3])&0x3f7f); +// mag->pnum = (mag->mag<<8)|((mag->sub&0x3f7f)<<16)|page; +// fprintf(stderr,"page: %x, pnum: %x, sub: %x\n",page,mag->pnum,mag->sub); + } + + if (mag->valid) { + if (line <= 23) { + memcpy(mag->pagebuf+40*line,data,40); + } + + if (line==23) { + sprintf(fname,"%s/%d/%03x_%02x.vtx",VTXDIR,pnr,mag->pnum+(mag->mag*0x100),mag->sub&0xff); +// fprintf(stderr,"Writing to file %s\n",fname); + if ((fd=fopen(fname,"w"))) { + fwrite("VTXV4",1,5,fd); + buf=0x01; fwrite(&buf,1,1,fd); + buf=mag->mag; fwrite(&buf,1,1,fd); + buf=mag->pnum; fwrite(&buf,1,1,fd); + buf=0x00; fwrite(&buf,1,1,fd); /* subpage?? */ + buf=0x00; fwrite(&buf,1,1,fd); + buf=0x00; fwrite(&buf,1,1,fd); + buf=0x00; fwrite(&buf,1,1,fd); + fwrite(mag->pagebuf,1,24*40,fd); + fclose(fd); + } + mag->valid=0; + } + } +} + +#ifdef NEWSTRUCT +void set_tt_filt(int fd,uint16_t tt_pid) +{ + struct dmx_pes_filter_params pesFilterParams; + + pesFilterParams.pid = tt_pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; + pesFilterParams.pes_type = DMX_PES_OTHER; + pesFilterParams.flags = DMX_IMMEDIATE_START; + + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + fprintf(stderr,"FILTER %i: ",tt_pid); + perror("DMX SET PES FILTER"); + } +} +#else +void set_tt_filt(int fd,uint16_t tt_pid) +{ + struct dmxPesFilterParams pesFilterParams; + + pesFilterParams.pid = tt_pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; + pesFilterParams.pesType = DMX_PES_OTHER; + pesFilterParams.flags = DMX_IMMEDIATE_START; + + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + fprintf(stderr,"FILTER %i: ",tt_pid); + perror("DMX SET PES FILTER"); + } +} +#endif + +int main(int argc, char **argv) +{ + int pid; + int i,j,n,m; + unsigned char buf[188]; /* data buffer */ + unsigned char mpag,mag,pack; + + int fd_dvr; + + /* Test channels - Astra 19E, 11837h, SR 27500 - e.g. ARD */ + int pids[MAX_CHANNELS]; + int pnrs[MAX_CHANNELS]={ 1,2,3,4,5,6,7,8 }; /* Directory names */ + + mag_struct mags[MAX_CHANNELS][8]; + int fd[MAX_CHANNELS]; + int count; + + printf("dvbtext v%s - (C) Dave Chapman 2001\n",VERSION); + printf("Latest version available from http://www.linuxstb.org/dvbtext\n"); + + if (argc==1) { + printf(USAGE); + return(-1); + } else { + count=0; + for (i=1;i 8) { + printf("\nSorry, you can only set up to 8 filters.\n\n"); + return(-1); + } else { + printf("Decoding %d teletext stream%s into %s/*\n",count,(count==1 ? "" : "s"),VTXDIR); + } + } else { + printf(USAGE); + return(-1); + } + + for (m=0;m 2001. + +The latest version can be found at http://www.linuxstb.org/dvbtext + +Thanks to: + +Ralph Metzler for his work on both the DVB driver and his old +vbidecode package (some code and ideas in dvbtext are borrowed +from vbidecode). + +Copyright notice: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#ifdef NEWSTRUCT +#include +#else +#include +#endif +#include "tables.h" + +#define VERSION "0.1" +#define VTXDIR "/run/ttxd/spool" +//#define VTXDIR "/opt/TTx_Server/spool" +//#define VTXDIR "/video/vtx" +#define USAGE "\nUSAGE: dvbtext tpid1 tpid2 tpid3 .. tpid8\n\n" + +// There seems to be a limit of 8 teletext streams - OK for most (but +// not all) transponders. +#define MAX_CHANNELS 9 + +typedef struct mag_struct_ { + int valid; + int mag; + unsigned char flags; + unsigned char lang; + int pnum,sub; + unsigned char pagebuf[25*40]; +} mag_struct; + +// FROM vbidecode +// unham 2 bytes into 1, report 2 bit errors but ignore them +unsigned char unham(unsigned char a,unsigned char b) +{ + unsigned char c1,c2; + + c1=unhamtab[a]; + c2=unhamtab[b]; +// if ((c1|c2)&0x40) +// fprintf(stderr,"bad ham!"); + return (c2<<4)|(0x0f&c1); +} + +void write_data(unsigned char* b, int n) { + int i; + + for (i=0;ivalid=1; + memset(mag->pagebuf,' ', 25*40); + mag->pnum=unham(data[0],data[1]); // The lower two (hex) numbers of page + if (mag->pnum==0xff) return; // These are filler lines. Can use to update clock +// fprintf(stderr,"pagenum: %03x\n",c+mag->mag*0x100); + mag->flags=unham(data[2],data[3])&0x80; + mag->flags|=(c&0x40)|((c>>2)&0x20); + c=unham(data[6],data[7]); + mag->flags|=((c<<4)&0x10)|((c<<2)&0x08)|(c&0x04)|((c>>1)&0x02)|((c>>4)&0x01); + mag->lang=((c>>5) & 0x07); + + mag->sub=(unham(data[4],data[5])<<8)|(unham(data[2],data[3])&0x3f7f); +// mag->pnum = (mag->mag<<8)|((mag->sub&0x3f7f)<<16)|page; +// fprintf(stderr,"page: %x, pnum: %x, sub: %x\n",page,mag->pnum,mag->sub); + } + + if (mag->valid) { + if (line <= 23) { + memcpy(mag->pagebuf+40*line,data,40); + } + + if (line==23) { + sprintf(fname,"%s/%d/%03x_%02x.vtx",VTXDIR,pnr,mag->pnum+(mag->mag*0x100),mag->sub&0xff); +// fprintf(stderr,"Writing to file %s\n",fname); + if ((fd=fopen(fname,"w"))) { + fwrite("VTXV4",1,5,fd); + buf=0x01; fwrite(&buf,1,1,fd); + buf=mag->mag; fwrite(&buf,1,1,fd); + buf=mag->pnum; fwrite(&buf,1,1,fd); + buf=0x00; fwrite(&buf,1,1,fd); /* subpage?? */ + buf=0x00; fwrite(&buf,1,1,fd); + buf=0x00; fwrite(&buf,1,1,fd); + buf=0x00; fwrite(&buf,1,1,fd); + fwrite(mag->pagebuf,1,24*40,fd); + fclose(fd); + } + mag->valid=0; + } + } +} + +#ifdef NEWSTRUCT +void set_tt_filt(int fd,uint16_t tt_pid) +{ + struct dmx_pes_filter_params pesFilterParams; + + pesFilterParams.pid = tt_pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; + pesFilterParams.pes_type = DMX_PES_OTHER; + pesFilterParams.flags = DMX_IMMEDIATE_START; + + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + fprintf(stderr,"FILTER %i: ",tt_pid); + perror("DMX SET PES FILTER"); + } +} +#else +void set_tt_filt(int fd,uint16_t tt_pid) +{ + struct dmxPesFilterParams pesFilterParams; + + pesFilterParams.pid = tt_pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; + pesFilterParams.pesType = DMX_PES_OTHER; + pesFilterParams.flags = DMX_IMMEDIATE_START; + + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + fprintf(stderr,"FILTER %i: ",tt_pid); + perror("DMX SET PES FILTER"); + } +} +#endif + +int main(int argc, char **argv) +{ + int pid; + int i,j,n,m; + unsigned char buf[188]; /* data buffer */ + unsigned char mpag,mag,pack; + + int fd_dvr; + + /* Test channels - Astra 19E, 11837h, SR 27500 - e.g. ARD */ + int pids[MAX_CHANNELS]; + int pnrs[MAX_CHANNELS]={ 1,2,3,4,5,6,7,8 }; /* Directory names */ + + mag_struct mags[MAX_CHANNELS][8]; + int fd[MAX_CHANNELS]; + int count; + + printf("dvbtext v%s - (C) Dave Chapman 2001\n",VERSION); + printf("Latest version available from http://www.linuxstb.org/dvbtext\n"); + + if (argc==1) { + printf(USAGE); + return(-1); + } else { + count=0; + for (i=1;i 8) { + printf("\nSorry, you can only set up to 8 filters.\n\n"); + return(-1); + } else { + printf("Decoding %d teletext stream%s into %s/*\n",count,(count==1 ? "" : "s"),VTXDIR); + } + } else { + printf(USAGE); + return(-1); + } + + for (m=0;m ../devices/pseudo/clone@0:tcp + And you also need the file it points to: + crw-rw-rw- bin 11, 42 May 24 21:32 /devices/pseudo/clone@0:tcp + You probably need some other files too, such as shared libraries and + a tmp directory. Check out the man page for ftpd, it has a big long + shell script for setting up an anonymous ftp area that should also + work for thttpd. diff --git a/src/thttpd-2.27/Makefile b/src/thttpd-2.27/Makefile new file mode 100644 index 0000000..025f8c3 --- /dev/null +++ b/src/thttpd-2.27/Makefile @@ -0,0 +1,174 @@ +# Generated automatically from Makefile.in by configure. +# Makefile.in for thttpd +# +# Copyright © 1995,1998 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# Various configurable paths (remember to edit Makefile.in, not Makefile) + +# Top level hierarchy. +prefix = /usr/local +exec_prefix = ${prefix} +# Pathname of directory to install the binary. +BINDIR = ${exec_prefix}/sbin +# Pathname of directory to install the man page. +MANDIR = ${prefix}/man +# Pathname of directory to install the CGI programs. +WEBDIR = $(prefix)/www + +# CONFIGURE: The group that the web directory belongs to. This is so that +# the makeweb program can be installed set-group-id to that group, and make +# subdirectories. If you're not going to use makeweb, ignore this. +WEBGROUP = www + +# CONFIGURE: Directory for CGI executables. +CGIBINDIR = $(WEBDIR)/cgi-bin + +# You shouldn't need to edit anything below here. + +CC = gcc +CCOPT = -O2 +DEFS = -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 +INCLS = -I. +CFLAGS = $(CCOPT) $(DEFS) $(INCLS) +LDFLAGS = +LIBS = -lcrypt +NETLIBS = +INSTALL = /usr/bin/install -c + + + +.c.o: + @rm -f $@ + $(CC) $(CFLAGS) -c $*.c + +SRC = thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c + +OBJ = $(SRC:.c=.o) + +ALL = thttpd + +GENHDR = mime_encodings.h mime_types.h + +CLEANFILES = $(ALL) $(OBJ) $(GENSRC) $(GENHDR) + +SUBDIRS = cgi-src extras + +all: this subdirs +this: $(ALL) + +thttpd: $(OBJ) + @rm -f $@ + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS) + +mime_encodings.h: mime_encodings.txt + rm -f mime_encodings.h + sed < mime_encodings.txt > mime_encodings.h \ + -e 's/#.*//' -e 's/[ ]*$$//' -e '/^$$/d' \ + -e 's/[ ][ ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/' + +mime_types.h: mime_types.txt + rm -f mime_types.h + sed < mime_types.txt > mime_types.h \ + -e 's/#.*//' -e 's/[ ]*$$//' -e '/^$$/d' \ + -e 's/[ ][ ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/' + + +subdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) \ + WEBDIR=$(WEBDIR) \ + CGIBINDIR=$(CGIBINDIR) \ + MANDIR=$(MANDIR) \ + WEBGROUP=$(WEBGROUP) \ + ) ; done + + +install: installthis install-man installsubdirs + +installthis: + -mkdir -p $(DESTDIR)$(BINDIR) + $(INSTALL) -m 555 -o bin -g bin thttpd $(DESTDIR)$(BINDIR) + +install-man: + -mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 444 -o bin -g bin thttpd.8 $(DESTDIR)$(MANDIR)/man8 + +installsubdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) \ + WEBDIR=$(WEBDIR) \ + CGIBINDIR=$(CGIBINDIR) \ + MANDIR=$(MANDIR) \ + WEBGROUP=$(WEBGROUP) \ + install \ + ) ; done + + +clean: cleansubdirs + rm -f $(CLEANFILES) + +distclean: distcleansubdirs + rm -f $(CLEANFILES) Makefile config.cache config.log config.status tags + +cleansubdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) clean \ + ) ; done + +distcleansubdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) distclean \ + ) ; done + +tags: + ctags -wtd *.c *.h + +tar: + @name=`sed -n -e '/SERVER_SOFTWARE/!d' -e 's,.*thttpd/,thttpd-,' -e 's, .*,,p' version.h` ; \ + rm -rf $$name ; \ + mkdir $$name ; \ + tar cf - `cat FILES` | ( cd $$name ; tar xfBp - ) ; \ + chmod 644 $$name/Makefile.in $$name/config.h $$name/mime_encodings.txt $$name/mime_types.txt ; \ + chmod 755 $$name/cgi-bin $$name/cgi-src $$name/contrib $$name/contrib/redhat-rpm $$name/extras $$name/scripts ; \ + tar cf $$name.tar $$name ; \ + rm -rf $$name ; \ + gzip $$name.tar + +thttpd.o: config.h version.h libhttpd.h fdwatch.h mmc.h timers.h match.h +libhttpd.o: config.h version.h libhttpd.h mime_encodings.h mime_types.h \ + mmc.h timers.h match.h tdate_parse.h +fdwatch.o: fdwatch.h +mmc.o: mmc.h libhttpd.h +timers.o: timers.h +match.o: match.h +tdate_parse.o: tdate_parse.h diff --git a/src/thttpd-2.27/Makefile.in b/src/thttpd-2.27/Makefile.in new file mode 100644 index 0000000..ded71e0 --- /dev/null +++ b/src/thttpd-2.27/Makefile.in @@ -0,0 +1,173 @@ +# Makefile.in for thttpd +# +# Copyright © 1995,1998 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# Various configurable paths (remember to edit Makefile.in, not Makefile) + +# Top level hierarchy. +prefix = @prefix@ +exec_prefix = @exec_prefix@ +# Pathname of directory to install the binary. +BINDIR = @sbindir@ +# Pathname of directory to install the man page. +MANDIR = @mandir@ +# Pathname of directory to install the CGI programs. +WEBDIR = $(prefix)/www + +# CONFIGURE: The group that the web directory belongs to. This is so that +# the makeweb program can be installed set-group-id to that group, and make +# subdirectories. If you're not going to use makeweb, ignore this. +WEBGROUP = www + +# CONFIGURE: Directory for CGI executables. +CGIBINDIR = $(WEBDIR)/cgi-bin + +# You shouldn't need to edit anything below here. + +CC = @CC@ +CCOPT = @V_CCOPT@ +DEFS = @DEFS@ +INCLS = -I. +CFLAGS = $(CCOPT) $(DEFS) $(INCLS) +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +NETLIBS = @V_NETLIBS@ +INSTALL = @INSTALL@ + +@SET_MAKE@ + +.c.o: + @rm -f $@ + $(CC) $(CFLAGS) -c $*.c + +SRC = thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c + +OBJ = $(SRC:.c=.o) @LIBOBJS@ + +ALL = thttpd + +GENHDR = mime_encodings.h mime_types.h + +CLEANFILES = $(ALL) $(OBJ) $(GENSRC) $(GENHDR) + +SUBDIRS = cgi-src extras + +all: this subdirs +this: $(ALL) + +thttpd: $(OBJ) + @rm -f $@ + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS) + +mime_encodings.h: mime_encodings.txt + rm -f mime_encodings.h + sed < mime_encodings.txt > mime_encodings.h \ + -e 's/#.*//' -e 's/[ ]*$$//' -e '/^$$/d' \ + -e 's/[ ][ ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/' + +mime_types.h: mime_types.txt + rm -f mime_types.h + sed < mime_types.txt > mime_types.h \ + -e 's/#.*//' -e 's/[ ]*$$//' -e '/^$$/d' \ + -e 's/[ ][ ]*/", 0, "/' -e 's/^/{ "/' -e 's/$$/", 0 },/' + + +subdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) \ + WEBDIR=$(WEBDIR) \ + CGIBINDIR=$(CGIBINDIR) \ + MANDIR=$(MANDIR) \ + WEBGROUP=$(WEBGROUP) \ + ) ; done + + +install: installthis install-man installsubdirs + +installthis: + -mkdir -p $(DESTDIR)$(BINDIR) + $(INSTALL) -m 555 -o bin -g bin thttpd $(DESTDIR)$(BINDIR) + +install-man: + -mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 444 -o bin -g bin thttpd.8 $(DESTDIR)$(MANDIR)/man8 + +installsubdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) \ + WEBDIR=$(WEBDIR) \ + CGIBINDIR=$(CGIBINDIR) \ + MANDIR=$(MANDIR) \ + WEBGROUP=$(WEBGROUP) \ + install \ + ) ; done + + +clean: cleansubdirs + rm -f $(CLEANFILES) + +distclean: distcleansubdirs + rm -f $(CLEANFILES) Makefile config.cache config.log config.status tags + +cleansubdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) clean \ + ) ; done + +distcleansubdirs: + for i in $(SUBDIRS) ; do ( \ + cd $$i ; \ + pwd ; \ + $(MAKE) $(MFLAGS) distclean \ + ) ; done + +tags: + ctags -wtd *.c *.h + +tar: + @name=`sed -n -e '/SERVER_SOFTWARE/!d' -e 's,.*thttpd/,thttpd-,' -e 's, .*,,p' version.h` ; \ + rm -rf $$name ; \ + mkdir $$name ; \ + tar cf - `cat FILES` | ( cd $$name ; tar xfBp - ) ; \ + chmod 644 $$name/Makefile.in $$name/config.h $$name/mime_encodings.txt $$name/mime_types.txt ; \ + chmod 755 $$name/cgi-bin $$name/cgi-src $$name/contrib $$name/contrib/redhat-rpm $$name/extras $$name/scripts ; \ + tar cf $$name.tar $$name ; \ + rm -rf $$name ; \ + gzip $$name.tar + +thttpd.o: config.h version.h libhttpd.h fdwatch.h mmc.h timers.h match.h +libhttpd.o: config.h version.h libhttpd.h mime_encodings.h mime_types.h \ + mmc.h timers.h match.h tdate_parse.h +fdwatch.o: fdwatch.h +mmc.o: mmc.h libhttpd.h +timers.o: timers.h +match.o: match.h +tdate_parse.o: tdate_parse.h diff --git a/src/thttpd-2.27/README b/src/thttpd-2.27/README new file mode 100644 index 0000000..9422b97 --- /dev/null +++ b/src/thttpd-2.27/README @@ -0,0 +1,31 @@ + thttpd - tiny/turbo/throttling HTTP server + version 2.27 of 19Oct2015 + +thttpd is a simple, small, portable, fast, and secure HTTP server. + +Simple: It handles only the minimum necessary to implement HTTP/1.1. + +Small: See the size comparison chart at +http://www.acme.com/software/thttpd/notes.html#sizes. It also has a +very small run-time size, since it does not fork and is very careful about +memory allocation. + +Portable: It compiles cleanly on FreeBSD 2.x/3.x, SunOS 4.1.x, Solaris 2.x, +BSD/OS 2.x, Linux 1.2.x, OSF/1 (on a 64-bit Alpha), and no doubt many others. + +Fast: In typical use it's about as fast as the best full-featured servers +(Apache, NCSA, Netscape). Under extreme load it's much faster. + +Secure: It goes to great lengths to protect the web server machine +against attacks and breakins from other sites. + +It also has one extremely useful feature (URL-traffic-based throttling) that +no other server currently has. + +See the manual entry for more details. See the INSTALL file for +configuration and installation instructions. Check the web page +(http://www.acme.com/software/thttpd/) for updates, or add yourself to +the mailing list by sending a "subscribe" to thttpd-announce-request@mail.acme.com. + +Comments to: + Jef Poskanzer jef@mail.acme.com http://www.acme.com/jef/ diff --git a/src/thttpd-2.27/TODO b/src/thttpd-2.27/TODO new file mode 100644 index 0000000..ab5dd21 --- /dev/null +++ b/src/thttpd-2.27/TODO @@ -0,0 +1,80 @@ +- - - - - - - - - - high priority - - - - - - - - - - + +IPv6 not working right. + +Problem with ACME News downloads. PATH_INFO interferes with the authorization. + +Why is the client's IP address showing up in paths? + +Fetches with numeric IP addresses and no Host: header are screwing up the +vhost code? +143.90.193.229 - - [06/Apr/2000:09:21:34 -0700] "GET /209.133.38.22/software/thttpd/ HTTP/1.0" 200 12093 "http://www.dbphotography.demon.co.uk/index.html" "Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)" +143.90.193.229 - - [06/Apr/2000:09:21:37 -0700] "GET /143.90.193.229/software/thttpd/anvil_thttpd.gif HTTP/1.0" 403 - "http://www.acme.com/software/thttpd/" "Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)" + +Have directory indexing skip files that start with dot? Except ..? +In libhttpd.c: ++ if (*(de->d_name) == '.' && *(de->d_name+1) != '.') ++ continue; + namlen = NAMLEN(de); + +Add comment on INDEX_NAMES that it should be simple filenames only. + +The error page generated for non-local referers should include the +original URL as an active link. + +Make open in mmc.c use O_NONBLOCK flag, to prevent DOS attack via +a named pipe? + +- - - - - - - - - - later - - - - - - - - - - + +Document how symlinks interact with .htpasswd - authorization is checked +on the result of the symlink, and not the origin. + +SIGHUP log re-opening doesn't work if you started as root. + +Change redirect to put the Refresh command in the HTTP headers, instead of +a META tag. + +Add TCP_NODELAY, but after CGIs get spawned. + +Add stat cache? 1 minute expiry? + +Ifdef the un-close-on-exec CGI thing for Linux only. + +Add keep-alives, via a new state in thttpd.c. + +- - - - - - - - - - someday - - - - - - - - - - + +The special world-permissions checking is probably bogus. For one +thing, it doesn't handle restrictive permissions on parent directories +properly. It should probably just go away. + +redirect should interpret a path with a trailing / as /index.html + +ssi should change $cwd to the source document's location. + +Allow .throttle files in individual directories. + +Log-digesting scripts. + +Config web page. + Common errors: + Not realizing that -c overrides CGI_PATTERN instead of augmenting it. + Using a directory name for the -c pattern. + +- - - - - - - - - - 3.x - - - - - - - - - - + +Tasklets re-write. + +- - - - - - - - - - general - - - - - - - - - - + +Release process: + - update version number in version.h README INSTALL and + contrib/redhat-rpm/thttpd.spec + - do a tdiff and update the local installation + - do an rcstreeinfo, and check in all files + - make tar + - mv it to .. + - update version number in ../thttpd.html + - update ~acmeweb/updates.html + - mail announcement to thttpd-announce diff --git a/src/thttpd-2.27/aclocal.m4 b/src/thttpd-2.27/aclocal.m4 new file mode 100644 index 0000000..ff35a25 --- /dev/null +++ b/src/thttpd-2.27/aclocal.m4 @@ -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 +# include ], + [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 ], + [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 +# include ], + [socklen_t slen], + ac_cv_acme_socklen_t=yes, + ac_cv_acme_socklen_t=no)) + AC_MSG_RESULT($ac_cv_acme_socklen_t) + if test $ac_cv_acme_socklen_t = yes ; then + AC_DEFINE(HAVE_SOCKLENT) + fi]) diff --git a/src/thttpd-2.27/cgi-bin/printenv b/src/thttpd-2.27/cgi-bin/printenv new file mode 100755 index 0000000..cb5df7e --- /dev/null +++ b/src/thttpd-2.27/cgi-bin/printenv @@ -0,0 +1,29 @@ +#!/bin/sh + +date=`date -u '+%a, %d %b %Y %H:%M:%S %Z'` + +cat << EOF +Content-type: text/plain +Expires: $date + +CGI printenv + +EOF + +echo 'Date:' +date +echo +echo 'Id:' +id +echo +echo 'Env:' +printenv +echo +if [ "$CONTENT_LENGTH" != "" ] ; then + if [ "$CONTENT_LENGTH" -ne 0 ] ; then + echo 'Input:' + echo + dd bs=1 count=$CONTENT_LENGTH + echo + fi +fi diff --git a/src/thttpd-2.27/cgi-src/Makefile b/src/thttpd-2.27/cgi-src/Makefile new file mode 100644 index 0000000..67e6d9b --- /dev/null +++ b/src/thttpd-2.27/cgi-src/Makefile @@ -0,0 +1,87 @@ +# Generated automatically from Makefile.in by configure. +# Makefile for cgi-src +# +# Copyright © 1995 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +prefix = /usr/local +exec_prefix = ${prefix} +WEBDIR = $(prefix)/www +CGIBINDIR = $(WEBDIR)/cgi-bin +MANDIR = ${prefix}/man + +CC = gcc +CCOPT = -O2 +DEFS = -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 +INCLS = -I.. +CFLAGS = $(CCOPT) $(DEFS) $(INCLS) +LDFLAGS = +LIBS = -lcrypt +NETLIBS = +INSTALL = /usr/bin/install -c + +CLEANFILES = *.o redirect ssi phf + + + +.c.o: + @rm -f $@ + $(CC) $(CFLAGS) -c $*.c + +all: redirect ssi phf + +redirect: redirect.o + $(CC) $(LDFLAGS) $(STATICFLAG) redirect.o $(LIBS) -o redirect + +ssi: ssi.o ../match.o + $(CC) $(LDFLAGS) $(STATICFLAG) ssi.o ../match.o $(LIBS) -o ssi + +ssi.o: ../match.h + +phf: phf.o + $(CC) $(LDFLAGS) $(STATICFLAG) phf.o $(LIBS) -o phf + +strerror.o: + @rm -f strerror.o + @ln -s ../strerror.o + cd .. ; $(MAKE) $(MFLAGS) strerror.o + +install: all + -mkdir -p $(CGIBINDIR) + rm -f $(CGIBINDIR)/redirect + cp redirect $(CGIBINDIR)/redirect + rm -f $(MANDIR)/man8/redirect.8 + cp redirect.8 $(MANDIR)/man8/redirect.8 + rm -f $(CGIBINDIR)/ssi + cp ssi $(CGIBINDIR)/ssi + rm -f $(MANDIR)/man8/ssi.8 + cp ssi.8 $(MANDIR)/man8/ssi.8 + rm -f $(CGIBINDIR)/phf + cp phf $(CGIBINDIR)/phf + +clean: + rm -f $(CLEANFILES) + +distclean: + rm -f $(CLEANFILES) Makefile diff --git a/src/thttpd-2.27/cgi-src/Makefile.in b/src/thttpd-2.27/cgi-src/Makefile.in new file mode 100644 index 0000000..6e4e9ba --- /dev/null +++ b/src/thttpd-2.27/cgi-src/Makefile.in @@ -0,0 +1,86 @@ +# Makefile for cgi-src +# +# Copyright © 1995 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +WEBDIR = $(prefix)/www +CGIBINDIR = $(WEBDIR)/cgi-bin +MANDIR = @mandir@ + +CC = @CC@ +CCOPT = @V_CCOPT@ +DEFS = @DEFS@ +INCLS = -I.. +CFLAGS = $(CCOPT) $(DEFS) $(INCLS) +LDFLAGS = @LDFLAGS@ @V_STATICFLAG@ +LIBS = @LIBS@ +NETLIBS = @V_NETLIBS@ +INSTALL = @INSTALL@ + +CLEANFILES = *.o redirect ssi phf + +@SET_MAKE@ + +.c.o: + @rm -f $@ + $(CC) $(CFLAGS) -c $*.c + +all: redirect ssi phf + +redirect: redirect.o + $(CC) $(LDFLAGS) $(STATICFLAG) redirect.o $(LIBS) -o redirect + +ssi: ssi.o ../match.o + $(CC) $(LDFLAGS) $(STATICFLAG) ssi.o ../match.o $(LIBS) -o ssi + +ssi.o: ../match.h + +phf: phf.o + $(CC) $(LDFLAGS) $(STATICFLAG) phf.o $(LIBS) -o phf + +strerror.o: + @rm -f strerror.o + @ln -s ../strerror.o + cd .. ; $(MAKE) $(MFLAGS) strerror.o + +install: all + -mkdir -p $(CGIBINDIR) + rm -f $(CGIBINDIR)/redirect + cp redirect $(CGIBINDIR)/redirect + rm -f $(MANDIR)/man8/redirect.8 + cp redirect.8 $(MANDIR)/man8/redirect.8 + rm -f $(CGIBINDIR)/ssi + cp ssi $(CGIBINDIR)/ssi + rm -f $(MANDIR)/man8/ssi.8 + cp ssi.8 $(MANDIR)/man8/ssi.8 + rm -f $(CGIBINDIR)/phf + cp phf $(CGIBINDIR)/phf + +clean: + rm -f $(CLEANFILES) + +distclean: + rm -f $(CLEANFILES) Makefile diff --git a/src/thttpd-2.27/cgi-src/phf.c b/src/thttpd-2.27/cgi-src/phf.c new file mode 100644 index 0000000..6d06b65 --- /dev/null +++ b/src/thttpd-2.27/cgi-src/phf.c @@ -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 . +** 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 +#include +#include +#include + +#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\ +404 Not Found\n\ +

404 Not Found

\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\ +\n" ); + exit( 0 ); + } diff --git a/src/thttpd-2.27/cgi-src/redirect.8 b/src/thttpd-2.27/cgi-src/redirect.8 new file mode 100644 index 0000000..69a96e1 --- /dev/null +++ b/src/thttpd-2.27/cgi-src/redirect.8 @@ -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 . +All rights reserved. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. diff --git a/src/thttpd-2.27/cgi-src/redirect.c b/src/thttpd-2.27/cgi-src/redirect.c new file mode 100644 index 0000000..d1caac0 --- /dev/null +++ b/src/thttpd-2.27/cgi-src/redirect.c @@ -0,0 +1,215 @@ +/* redirect - simple redirection CGI program +** +** Copyright © 1995 by Jef Poskanzer . +** 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 + +#include +#include +#include + +#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\ +%s\n\ +

%s

\n\ +Something unusual went wrong during a redirection request:\n\ +
\n\ +%s\n\ +
\n\ +\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\ +%s\n\ +

%s

\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\ +\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\ +%s\n\ +

%s

\n\ +The requested filename, %s, has moved to a new URL:\n\ +%s.\n\ +\n", url, title, title, script_name, url, url ); + } + + +int +main( int argc, char** argv ) + { + char* script_name; + char* path_info; + char* cp; + FILE* fp; + char *star; + char buf[5000], file[5000], url[5000]; + + argv0 = argv[0]; + + /* Get the name that we were run as, which is the filename being + ** redirected. + */ + script_name = getenv( "SCRIPT_NAME" ); + if ( script_name == (char*) 0 ) + { + internal_error( "Couldn't get SCRIPT_NAME environment variable." ); + exit( 1 ); + } + + /* Append the PATH_INFO, if any. This allows redirection of whole + ** directories. + */ + path_info = getenv( "PATH_INFO" ); + if ( path_info != (char*) 0 ) + { + cp = (char*) malloc( strlen( script_name ) + strlen( path_info ) + 1 ); + if ( cp == (char*) 0 ) + { + internal_error( "Out of memory." ); + exit( 1 ); + } + (void) sprintf( cp, "%s%s", script_name, path_info ); + script_name = cp; + } + + /* Open the redirects file. */ + fp = fopen( ".redirects", "r" ); + if ( fp == (FILE*) 0 ) + { + internal_error( "Couldn't open .redirects file." ); + exit( 1 ); + } + + /* Search the file for a matching entry. */ + while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 ) + { + /* Remove comments. */ + cp = strchr( buf, '#' ); + if ( cp != (char*) 0 ) + *cp = '\0'; + /* Skip leading whitespace. */ + cp = buf; + cp += strspn( cp, " \t" ); + /* Check for blank line. */ + if ( *cp != '\0' ) + { + /* Parse line. */ + if ( sscanf( cp, "%[^ \t\n] %[^ \t\n]", file, url ) == 2 ) + { + /* Check for wildcard match. */ + star = strchr( file, '*' ); + if ( star != (char*) 0 ) + { + /* Check for leading match. */ + if ( strncmp( file, script_name, star - file ) == 0 ) + { + /* Got it; put together the full name. */ + strcat( url, script_name + ( star - file ) ); + /* XXX Whack the script_name, too? */ + moved( script_name, url ); + exit( 0 ); + } + } + /* Check for exact match. */ + if ( strcmp( file, script_name ) == 0 ) + { + /* Got it. */ + moved( script_name, url ); + exit( 0 ); + } + } + } + } + + /* No match found. */ + not_found( script_name ); + exit( 1 ); + } diff --git a/src/thttpd-2.27/cgi-src/ssi.8 b/src/thttpd-2.27/cgi-src/ssi.8 new file mode 100644 index 0000000..01c2045 --- /dev/null +++ b/src/thttpd-2.27/cgi-src/ssi.8 @@ -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 + +.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 . +All rights reserved. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. diff --git a/src/thttpd-2.27/cgi-src/ssi.c b/src/thttpd-2.27/cgi-src/ssi.c new file mode 100644 index 0000000..1b0950d --- /dev/null +++ b/src/thttpd-2.27/cgi-src/ssi.c @@ -0,0 +1,763 @@ +/* ssi - server-side-includes CGI program +** +** Copyright © 1995 by Jef Poskanzer . +** 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 +#include +#include +#include +#include +#include + +#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( "\ +%s\n\ +

%s

\n\ +Something unusual went wrong during a server-side-includes request:\n\ +
\n\ +%s\n\ +
\n\ +\n", title, title, reason ); + } + + +static void +not_found( char* filename ) + { + char* title = "404 Not Found"; + + (void) printf( "\ +%s\n\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +does not seem to exist.\n\ +\n", title, title, filename ); + } + + +static void +not_found2( char* directive, char* tag, char* filename2 ) + { + char* title = "Not Found"; + + (void) printf( "\ +

%s

\n\ +The filename requested in a %s %s directive, %s,\n\ +does not seem to exist.\n\ +
\n", title, directive, tag, filename2 ); + } + + +static void +not_permitted( char* directive, char* tag, char* val ) + { + char* title = "Not Permitted"; + + (void) printf( "\ +

%s

\n\ +The filename requested in the %s %s=%s directive\n\ +may not be fetched.\n\ +
\n", title, directive, tag, val ); + } + + +static void +unknown_directive( char* filename, char* directive ) + { + char* title = "Unknown Directive"; + + (void) printf( "\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +tried to use an unknown directive, %s.\n\ +
\n", title, filename, directive ); + } + + +static void +unknown_tag( char* filename, char* directive, char* tag ) + { + char* title = "Unknown Tag"; + + (void) printf( "\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +tried to use the directive %s with an unknown tag, %s.\n\ +
\n", title, filename, directive, tag ); + } + + +static void +unknown_value( char* filename, char* directive, char* tag, char* val ) + { + char* title = "Unknown Value"; + + (void) printf( "\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +tried to use the directive %s %s with an unknown value, %s.\n\ +
\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 ( ". +# 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 + + 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 + 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 </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' /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 . + # 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 + 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 < +# include +#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 + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/src/thttpd-2.27/config.h b/src/thttpd-2.27/config.h new file mode 100644 index 0000000..65ab1e3 --- /dev/null +++ b/src/thttpd-2.27/config.h @@ -0,0 +1,392 @@ +/* config.h - configuration defines for thttpd and libhttpd +** +** Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer . +** 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 /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 /. The postfix would be +** the name of a subdirectory off of the user's actual home dir, something +** like "public_html". This is what Apache and other servers do. The problem +** is, you can't do this and chroot() at the same time, so it's inherently +** a security hole. This is strongly dis-recommended, but it's here because +** some people really want it. Use at your own risk. +** +** You can also leave both options undefined, and thttpd will not do +** anything special about tildes. Enabling both options is an error. +*/ +#ifdef notdef +#define TILDE_MAP_1 "users" +#define TILDE_MAP_2 "public_html" +#endif + +/* CONFIGURE: The file to use for authentication. If this is defined then +** thttpd checks for this file in the local directory before every fetch. +** If the file exists then authentication is done, otherwise the fetch +** proceeds as usual. +** +** If you undefine this then thttpd will not implement authentication +** at all and will not check for auth files, which saves a bit of CPU time. +*/ +#define AUTH_FILE ".htpasswd" + +/* CONFIGURE: The default character set name to use with text MIME types. +** This gets substituted into the MIME types where they have a "%s". +** +** You can override this in the config file with the "charset" setting, +** or on the command like with the -T flag. +*/ +#define DEFAULT_CHARSET "UTF-8" + + +/* Most people won't want to change anything below here. */ + +/* CONFIGURE: This controls the SERVER_NAME environment variable that gets +** passed to CGI programs. By default thttpd does a gethostname(), which +** gives the host's canonical name. If you want to always use some other name +** you can define it here. +** +** Alternately, if you want to run the same thttpd binary on multiple +** machines, and want to build in alternate names for some or all of +** them, you can define a list of canonical name to altername name +** mappings. thttpd seatches the list and when it finds a match on +** the canonical name, that alternate name gets used. If no match +** is found, the canonical name gets used. +** +** If both SERVER_NAME and SERVER_NAME_LIST are defined here, thttpd searches +** the list as above, and if no match is found then SERVER_NAME gets used. +** +** In any case, if thttpd is started with the -h flag, that name always +** gets used. +*/ +#ifdef notdef +#define SERVER_NAME "your.hostname.here" +#define SERVER_NAME_LIST \ + "canonical.name.here/alternate.name.here", \ + "canonical.name.two/alternate.name.two" +#endif + +/* CONFIGURE: Undefine this if you want thttpd to hide its specific version +** when returning into to browsers. Instead it'll just say "thttpd" with +** no version. +*/ +#define SHOW_SERVER_VERSION + +/* CONFIGURE: Define this if you want to always chroot(), without having +** to give the -r command line flag. Some people like this as a security +** measure, to prevent inadvertant exposure by accidentally running without -r. +** You can still disable it at runtime with the -nor flag. +*/ +#ifdef notdef +#define ALWAYS_CHROOT +#endif + +/* CONFIGURE: Define this if you want to always do virtual hosting, without +** having to give the -v command line flag. You can still disable it at +** runtime with the -nov flag. +*/ +#ifdef notdef +#define ALWAYS_VHOST +#endif + +/* CONFIGURE: If you're using the vhost feature and you have a LOT of +** virtual hostnames (like, hundreds or thousands), you will want to +** enable this feature. It avoids a problem with most Unix filesystems, +** where if there are a whole lot of items in a directory then name lookup +** becomes very slow. This feature makes thttpd use subdirectories +** based on the first characters of each hostname. You can set it to use +** from one to three characters. If the hostname starts with "www.", that +** part is skipped over. Dots are also skipped over, and if the name isn't +** long enough then "_"s are used. Here are some examples of how hostnames +** would get turned into directory paths, for each different setting: +** 1: www.acme.com -> a/www.acme.com +** 1: foobar.acme.com -> f/foobar.acme.com +** 2: www.acme.com -> a/c/www.acme.com +** 2: foobar.acme.com -> f/o/foobar.acme.com +** 3: www.acme.com -> a/c/m/www.acme.com +** 3: foobar.acme.com -> f/o/o/foobar.acme.com +** 3: m.tv -> m/t/v/m.tv +** 4: m.tv -> m/t/v/_/m.tv +** Note that if you compile this setting in but then forget to set up +** the corresponding subdirectories, the only error indication you'll +** get is a "404 Not Found" when you try to visit a site. So be careful. +*/ +#ifdef notdef +#define VHOST_DIRLEVELS 1 +#define VHOST_DIRLEVELS 2 +#define VHOST_DIRLEVELS 3 +#endif + +/* CONFIGURE: Define this if you want to always use a global passwd file, +** without having to give the -P command line flag. You can still disable +** it at runtime with the -noP flag. +*/ +#ifdef notdef +#define ALWAYS_GLOBAL_PASSWD +#endif + +/* CONFIGURE: When started as root, the default username to switch to after +** initializing. If this user (or the one specified by the -u flag) does +** not exist, the program will refuse to run. +*/ +#define DEFAULT_USER "nobody" + +/* CONFIGURE: When started as root, the program can automatically chdir() +** to the home directory of the user specified by -u or DEFAULT_USER. +** An explicit -d still overrides this. +*/ +#ifdef notdef +#define USE_USER_DIR +#endif + +/* CONFIGURE: If this is defined, some of the built-in error pages will +** have more explicit information about exactly what the problem is. +** Some sysadmins don't like this, for security reasons. +*/ +#define EXPLICIT_ERROR_PAGES + +/* CONFIGURE: Subdirectory for custom error pages. The error filenames are +** $WEBDIR/$ERR_DIR/err%d.html - if virtual hosting is enabled then +** $WEBDIR/hostname/$ERR_DIR/err%d.html is searched first. This allows +** different custom error pages for each virtual hosting web server. If +** no custom page for a given error can be found, the built-in error page +** is generated. If ERR_DIR is not defined at all, only the built-in error +** pages will be generated. +*/ +#define ERR_DIR "errors" + +/* CONFIGURE: Define this if you want a standard HTML tail containing +** $SERVER_SOFTWARE and $SERVER_ADDRESS to be appended to the custom error +** pages. (It is always appended to the built-in error pages.) +*/ +#define ERR_APPEND_SERVER_INFO + +/* CONFIGURE: nice(2) value to use for CGI programs. If this is undefined, +** CGI programs run at normal priority. +*/ +#define CGI_NICE 10 + +/* CONFIGURE: $PATH to use for CGI programs. +*/ +#define CGI_PATH "/usr/local/bin:/usr/ucb:/bin:/usr/bin" + +/* CONFIGURE: If defined, $LD_LIBRARY_PATH to use for CGI programs. +*/ +#ifdef notdef +#define CGI_LD_LIBRARY_PATH "/usr/local/lib:/usr/lib" +#endif + +/* CONFIGURE: How often to run the occasional cleanup job. +*/ +#define OCCASIONAL_TIME 120 + +/* CONFIGURE: Seconds between stats syslogs. If this is undefined then +** no stats are accumulated and no stats syslogs are done. +*/ +#define STATS_TIME 3600 + +/* CONFIGURE: The mmap cache tries to keep the total number of mapped +** files below this number, so you don't run out of kernel file descriptors. +** If you have reconfigured your kernel to have more descriptors, you can +** raise this and thttpd will keep more maps cached. However it's not +** a hard limit, thttpd will go over it if you really are accessing +** a whole lot of files. +*/ +#define DESIRED_MAX_MAPPED_FILES 1000 + +/* CONFIGURE: The mmap cache also tries to keep the total mapped bytes +** below this number, so you don't run out of address space. Again +** it's not a hard limit, thttpd will go over it if you really are +** accessing a bunch of large files. +*/ +#define DESIRED_MAX_MAPPED_BYTES 1000000000 + + +/* You almost certainly don't want to change anything below here. */ + +/* CONFIGURE: When throttling CGI programs, we don't know how many bytes +** they send back to the client because it would be inefficient to +** interpose a counter. CGI programs are much more expensive than +** regular files to serve, so we set an arbitrary and high byte count +** that gets applied to all CGI programs for throttling purposes. +*/ +#define CGI_BYTECOUNT 25000 + +/* CONFIGURE: The default port to listen on. 80 is the standard HTTP port. +*/ +#define DEFAULT_PORT 80 + +/* CONFIGURE: A list of index filenames to check. The files are searched +** for in this order. +*/ +#define INDEX_NAMES "index.html", "index.htm", "index.xhtml", "index.xht", "Default.htm", "index.cgi" + +/* CONFIGURE: If this is defined then thttpd will automatically generate +** index pages for directories that don't have an explicit index file. +** If you want to disable this behavior site-wide, perhaps for security +** reasons, just undefine this. Note that you can disable indexing of +** individual directories by merely doing a "chmod 711" on them - the +** standard Unix file permission to allow file access but disable "ls". +*/ +#define GENERATE_INDEXES + +/* CONFIGURE: Whether to log unknown request headers. Most sites will not +** want to log them, which will save them a bit of CPU time. +*/ +#ifdef notdef +#define LOG_UNKNOWN_HEADERS +#endif + +/* CONFIGURE: Whether to fflush() the log file after each request. If +** this is turned off there's a slight savings in CPU cycles. +*/ +#define FLUSH_LOG_EVERY_TIME + +/* CONFIGURE: Time between updates of the throttle table's rolling averages. */ +#define THROTTLE_TIME 2 + +/* CONFIGURE: The listen() backlog queue length. The 1024 doesn't actually +** get used, the kernel uses its maximum allowed value. This is a config +** parameter only in case there's some OS where asking for too high a queue +** length causes an error. Note that on many systems the maximum length is +** way too small - see http://www.acme.com/software/thttpd/notes.html +*/ +#define LISTEN_BACKLOG 1024 + +/* CONFIGURE: Maximum number of throttle patterns that any single URL can +** be included in. This has nothing to do with the number of throttle +** patterns that you can define, which is unlimited. +*/ +#define MAXTHROTTLENUMS 10 + +/* CONFIGURE: Number of file descriptors to reserve for uses other than +** connections. Currently this is 10, representing one for the listen fd, +** one for dup()ing at connection startup time, one for reading the file, +** one for syslog, and possibly one for the regular log file, which is +** five, plus a factor of two for who knows what. +*/ +#define SPARE_FDS 10 + +/* CONFIGURE: How many milliseconds to leave a connection open while doing a +** lingering close. +*/ +#define LINGER_TIME 500 + +/* CONFIGURE: Maximum number of symbolic links to follow before +** assuming there's a loop. +*/ +#define MAX_LINKS 32 + +/* CONFIGURE: You don't even want to know. +*/ +#define MIN_WOULDBLOCK_DELAY 100L + +#endif /* _CONFIG_H_ */ diff --git a/src/thttpd-2.27/config.log b/src/thttpd-2.27/config.log new file mode 100644 index 0000000..74e3981 --- /dev/null +++ b/src/thttpd-2.27/config.log @@ -0,0 +1,300 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +configure:573: checking host system type +configure:594: checking target system type +configure:612: checking build system type +configure:638: checking for gcc +configure:751: checking whether the C compiler (gcc ) works +configure:767: gcc -o conftest conftest.c 1>&5 +configure:764:1: warning: return type defaults to 'int' [-Wimplicit-int] + main(){return(0);} + ^ +configure:793: checking whether the C compiler (gcc ) is a cross-compiler +configure:798: checking whether we are using GNU C +configure:807: gcc -E conftest.c +configure:826: checking whether gcc accepts -g +configure:861: checking gcc version +configure:879: checking how to link static binaries +configure:910: checking for __progname +configure:923: gcc -o conftest -g -O2 conftest.c 1>&5 +configure: In function 'main': +configure:919:2: warning: implicit declaration of function 'puts' [-Wimplicit-function-declaration] + puts(__progname) + ^ +configure:946: checking how to run the C preprocessor +configure:967: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for fcntl.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for grp.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for memory.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for paths.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for poll.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for sys/poll.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1029: checking for sys/devpoll.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1035:25: fatal error: sys/devpoll.h: No such file or directory +compilation terminated. +configure: failed program was: +#line 1034 "configure" +#include "confdefs.h" +#include +configure:1029: checking for sys/event.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1035:23: fatal error: sys/event.h: No such file or directory +compilation terminated. +configure: failed program was: +#line 1034 "configure" +#include "confdefs.h" +#include +configure:1029: checking for osreldate.h +configure:1039: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1035:23: fatal error: osreldate.h: No such file or directory +compilation terminated. +configure: failed program was: +#line 1034 "configure" +#include "confdefs.h" +#include +configure:1066: checking whether time.h and sys/time.h may both be included +configure:1080: gcc -c -g -O2 conftest.c 1>&5 +configure:1105: checking for dirent.h that defines DIR +configure:1118: gcc -c -g -O2 conftest.c 1>&5 +configure:1143: checking for opendir in -ldir +configure:1162: gcc -o conftest -g -O2 conftest.c -ldir 1>&5 +/usr/bin/ld: cannot find -ldir +collect2: error: ld returned 1 exit status +configure: failed program was: +#line 1151 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +configure:1228: checking for /usr/local/v6/lib +configure:1238: checking for gethostbyname +configure:1266: gcc -o conftest -g -O2 conftest.c 1>&5 +configure:1451: checking for socket +configure:1479: gcc -o conftest -g -O2 conftest.c 1>&5 +configure:1580: checking for main in -linet6 +configure:1595: gcc -o conftest -g -O2 conftest.c -linet6 1>&5 +/usr/bin/ld: cannot find -linet6 +collect2: error: ld returned 1 exit status +configure: failed program was: +#line 1588 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +configure:1624: checking for crypt +configure:1652: gcc -o conftest -g -O2 conftest.c 1>&5 +/tmp/ccx7ffNR.o: In function `main': +/opt/TTx_Server/not-used/src/thttpd-2.27/configure:1646: undefined reference to `crypt' +collect2: error: ld returned 1 exit status +configure: failed program was: +#line 1629 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char crypt(); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_crypt) || defined (__stub___crypt) +choke me +#else +crypt(); +#endif + +; return 0; } +configure:1670: checking for crypt in -lcrypt +configure:1689: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1719: checking for hstrerror +configure:1747: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1810: checking for strerror +configure:1838: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for waitpid +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for vsnprintf +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1879:6: warning: conflicting types for built-in function 'vsnprintf' + char $ac_func(); + ^ +configure:1867: checking for daemon +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for setsid +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for setlogin +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure: In function 'main': +configure:1887:1: error: unknown type name 'choke' + choke me + ^ +configure: failed program was: +#line 1872 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char setlogin(); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char setlogin(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_setlogin) || defined (__stub___setlogin) +choke me +#else +setlogin(); +#endif + +; return 0; } +configure:1867: checking for getaddrinfo +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for getnameinfo +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for gai_strerror +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for kqueue +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +/tmp/cc9x26i7.o: In function `main': +/opt/TTx_Server/not-used/src/thttpd-2.27/configure:1889: undefined reference to `kqueue' +collect2: error: ld returned 1 exit status +configure: failed program was: +#line 1872 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char kqueue(); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char kqueue(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_kqueue) || defined (__stub___kqueue) +choke me +#else +kqueue(); +#endif + +; return 0; } +configure:1867: checking for sigset +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1867: checking for atoll +configure:1895: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:1923: checking for unistd.h +configure:1933: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1962: checking for getpagesize +configure:1990: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:2015: checking for working mmap +configure:2163: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:2094:7: warning: conflicting types for built-in function 'malloc' + char *malloc(); + ^ +configure: In function 'main': +configure:2104:13: warning: implicit declaration of function 'getpagesize' [-Wimplicit-function-declaration] + pagesize = getpagesize(); + ^ +configure:2111:3: warning: implicit declaration of function 'exit' [-Wimplicit-function-declaration] + exit(1); + ^ +configure:2111:3: warning: incompatible implicit declaration of built-in function 'exit' +configure:2111:3: note: include '' or provide a declaration of 'exit' +configure:2113:17: warning: implicit declaration of function 'rand' [-Wimplicit-function-declaration] + *(data + i) = rand(); + ^ +configure:2114:2: warning: implicit declaration of function 'umask' [-Wimplicit-function-declaration] + umask(0); + ^ +configure:2117:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2117:3: note: include '' or provide a declaration of 'exit' +configure:2118:6: warning: implicit declaration of function 'write' [-Wimplicit-function-declaration] + if (write(fd, data, pagesize) != pagesize) + ^ +configure:2119:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2119:3: note: include '' or provide a declaration of 'exit' +configure:2120:2: warning: implicit declaration of function 'close' [-Wimplicit-function-declaration] + close(fd); + ^ +configure:2129:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2129:3: note: include '' or provide a declaration of 'exit' +configure:2132:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2132:3: note: include '' or provide a declaration of 'exit' +configure:2133:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + ^ +configure:2136:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2136:3: note: include '' or provide a declaration of 'exit' +configure:2139:4: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2139:4: note: include '' or provide a declaration of 'exit' +configure:2150:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2150:3: note: include '' or provide a declaration of 'exit' +configure:2151:6: warning: implicit declaration of function 'read' [-Wimplicit-function-declaration] + if (read(fd, data3, pagesize) != pagesize) + ^ +configure:2152:3: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2152:3: note: include '' or provide a declaration of 'exit' +configure:2155:4: warning: incompatible implicit declaration of built-in function 'exit' + exit(1); + ^ +configure:2155:4: note: include '' or provide a declaration of 'exit' +configure:2157:2: warning: implicit declaration of function 'unlink' [-Wimplicit-function-declaration] + unlink("conftestmmap"); + ^ +configure:2158:2: warning: incompatible implicit declaration of built-in function 'exit' + exit(0); + ^ +configure:2158:2: note: include '' or provide a declaration of 'exit' +configure:2248: checking for select +configure:2276: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:2248: checking for poll +configure:2276: gcc -o conftest -g -O2 conftest.c -lcrypt 1>&5 +configure:2304: checking if struct tm has tm_gmtoff member +configure:2318: gcc -c -g -O2 conftest.c 1>&5 +configure:2338: checking if int64_t exists +configure:2351: gcc -c -g -O2 conftest.c 1>&5 +configure:2371: checking if socklen_t exists +configure:2385: gcc -c -g -O2 conftest.c 1>&5 +configure:2406: checking whether make sets ${MAKE} +configure:2444: checking for a BSD compatible install diff --git a/src/thttpd-2.27/config.status b/src/thttpd-2.27/config.status new file mode 100755 index 0000000..e536aa0 --- /dev/null +++ b/src/thttpd-2.27/config.status @@ -0,0 +1,180 @@ +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host TVServer: +# +# ./configure +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]" +for ac_option +do + case "$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion" + exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "./config.status generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "$ac_cs_usage"; exit 0 ;; + *) echo "$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=. +ac_given_INSTALL="/usr/bin/install -c" + +trap 'rm -fr Makefile cgi-src/Makefile extras/Makefile conftest*; exit 1' 1 2 15 + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g; + s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF +/^[ ]*VPATH[ ]*=[^:]*$/d + +s%@SHELL@%/bin/sh%g +s%@CFLAGS@%-g -O2%g +s%@CPPFLAGS@%%g +s%@CXXFLAGS@%%g +s%@FFLAGS@%%g +s%@DEFS@% -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 %g +s%@LDFLAGS@%%g +s%@LIBS@%-lcrypt %g +s%@exec_prefix@%${prefix}%g +s%@prefix@%/usr/local%g +s%@program_transform_name@%s,x,x,%g +s%@bindir@%${exec_prefix}/bin%g +s%@sbindir@%${exec_prefix}/sbin%g +s%@libexecdir@%${exec_prefix}/libexec%g +s%@datadir@%${prefix}/share%g +s%@sysconfdir@%${prefix}/etc%g +s%@sharedstatedir@%${prefix}/com%g +s%@localstatedir@%${prefix}/var%g +s%@libdir@%${exec_prefix}/lib%g +s%@includedir@%${prefix}/include%g +s%@oldincludedir@%/usr/include%g +s%@infodir@%${prefix}/info%g +s%@mandir@%${prefix}/man%g +s%@host@%%g +s%@host_alias@%x86_64-pc-linux-gnu%g +s%@host_cpu@%%g +s%@host_vendor@%%g +s%@host_os@%%g +s%@target@%%g +s%@target_alias@%x86_64-pc-linux-gnu%g +s%@target_cpu@%%g +s%@target_vendor@%%g +s%@target_os@%%g +s%@build@%%g +s%@build_alias@%x86_64-pc-linux-gnu%g +s%@build_cpu@%%g +s%@build_vendor@%%g +s%@build_os@%%g +s%@CC@%gcc%g +s%@CPP@%gcc -E%g +s%@LIBOBJS@%%g +s%@SET_MAKE@%%g +s%@INSTALL_PROGRAM@%${INSTALL}%g +s%@INSTALL_SCRIPT@%${INSTALL_PROGRAM}%g +s%@INSTALL_DATA@%${INSTALL} -m 644%g +s%@V_CCOPT@%-O2%g +s%@V_STATICFLAG@%%g +s%@V_NETLIBS@%%g + +CEOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi + +CONFIG_FILES=${CONFIG_FILES-"Makefile cgi-src/Makefile extras/Makefile"} +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + + + +exit 0 diff --git a/src/thttpd-2.27/config.sub b/src/thttpd-2.27/config.sub new file mode 100755 index 0000000..0432524 --- /dev/null +++ b/src/thttpd-2.27/config.sub @@ -0,0 +1,927 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \ + | arme[lb] | pyramid \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | we32k | ns16k | clipper | i370 | sh \ + | powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \ + | pdp11 | mips64el | mips64orion | mips64orionel \ + | sparc | sparclet | sparclite | sparc64) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[3456]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \ + | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \ + | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \ + | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \ + | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigados) + basic_machine=m68k-cbm + os=-amigados + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + basic_machine=mips-mips + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -unixware* | svr4*) + os=-sysv4 + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigados + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/src/thttpd-2.27/configure b/src/thttpd-2.27/configure new file mode 100755 index 0000000..bb2d78f --- /dev/null +++ b/src/thttpd-2.27/configure @@ -0,0 +1,2782 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=thttpd.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:573: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:594: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:612: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:638: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:668: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:719: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:751: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 762 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:767: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:793: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:798: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:826: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + +V_CCOPT="-O" +if test "$GCC" = yes ; then + echo $ac_n "checking gcc version""... $ac_c" 1>&6 +echo "configure:861: checking gcc version" >&5 + if eval "test \"`echo '$''{'ac_cv_lbl_gcc_vers'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_lbl_gcc_vers=`$CC -dumpversion 2>&1 | \ + sed -e 's/\..*//'` +fi + + echo "$ac_t""$ac_cv_lbl_gcc_vers" 1>&6 + if test "$ac_cv_lbl_gcc_vers" -gt 1 ; then + V_CCOPT="-O2" + fi +fi +if test -f .devel ; then + V_CCOPT="-g $V_CCOPT -ansi -pedantic -U__STRICT_ANSI__ -Wall -Wpointer-arith -Wshadow -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wno-long-long" +fi + +echo $ac_n "checking how to link static binaries""... $ac_c" 1>&6 +echo "configure:879: checking how to link static binaries" >&5 +if eval "test \"`echo '$''{'ac_cv_lbl_static_flag'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_lbl_static_flag=unknown + echo 'main() {}' > conftest.c + if test "$GCC" != yes ; then + trial_flag="-Bstatic" + test=`$CC $trial_flag -o conftest conftest.c 2>&1` + if test -z "$test" ; then + ac_cv_lbl_static_flag="$trial_flag" + fi + rm -f conftest + fi + if test "$ac_cv_lbl_static_flag" = unknown ; then + trial_flag="-static" + test=`$CC $trial_flag -o conftest conftest.c 2>&1` + if test -z "$test" ; then + ac_cv_lbl_static_flag="$trial_flag" + fi + rm -f conftest + fi + rm conftest.c +fi + +echo "$ac_t""$ac_cv_lbl_static_flag" 1>&6 +if test "$ac_cv_lbl_static_flag" != unknown ; then + V_STATICFLAG="$ac_cv_lbl_static_flag" +fi + +echo $ac_n "checking for __progname""... $ac_c" 1>&6 +echo "configure:910: checking for __progname" >&5 +if eval "test \"`echo '$''{'ac_cv_extern__progname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_extern__progname=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_extern__progname=no +fi +rm -f conftest* +fi + +if test $ac_cv_extern__progname = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE__PROGNAME 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:946: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:967: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:984: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1001: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/devpoll.h sys/event.h osreldate.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1029: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1039: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:1066: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:1080: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:1105: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:1118: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:1143: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:1184: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + + +d="/usr/local/v6/lib" +echo $ac_n "checking for $d""... $ac_c" 1>&6 +echo "configure:1228: checking for $d" >&5 +if test -d $d; then + echo "$ac_t""yes (Adding -L$d to LDFLAGS)" 1>&6 + LDFLAGS="$LDFLAGS -L$d" +else + echo "$ac_t""no" 1>&6 +fi + +V_NETLIBS="" +echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 +echo "configure:1238: checking for gethostbyname" >&5 +if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) +choke me +#else +gethostbyname(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1266: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_gethostbyname=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_gethostbyname=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +# Some OSes (eg. Solaris) place it in libnsl: + echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 +echo "configure:1285: checking for gethostbyname in -lnsl" >&5 +ac_lib_var=`echo nsl'_'gethostbyname'_' | sed 'y%./+- %__p__%'` +if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lnsl $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +# Some strange OSes (SINIX) have it in libsocket: + echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6 +echo "configure:1324: checking for gethostbyname in -lsocket" >&5 +ac_lib_var=`echo socket'_'gethostbyname'_' | sed 'y%./+- %__p__%'` +if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lsocket $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +# Unfortunately libsocket sometimes depends on libnsl. + # AC_CHECK_LIB's API is essentially broken so the + # following ugliness is necessary: + echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6 +echo "configure:1365: checking for gethostbyname in -lsocket" >&5 +ac_lib_var=`echo socket'_'gethostbyname'_'-lnsl | sed 'y%./+- %__p__%'` +if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket -lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lsocket -lnsl $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6 +echo "configure:1403: checking for gethostbyname in -lresolv" >&5 +ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lresolv $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lresolv $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +fi + +fi + +fi + +echo $ac_n "checking for socket""... $ac_c" 1>&6 +echo "configure:1451: checking for socket" >&5 +if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_socket) || defined (__stub___socket) +choke me +#else +socket(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_socket=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_socket=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 +echo "configure:1497: checking for socket in -lsocket" >&5 +ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lsocket $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 +echo "configure:1535: checking for socket in -lsocket" >&5 +ac_lib_var=`echo socket'_'socket'_'-lnsl | sed 'y%./+- %__p__%'` +if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket -lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lbl_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lsocket -lnsl $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +fi + + +echo $ac_n "checking for main in -linet6""... $ac_c" 1>&6 +echo "configure:1580: checking for main in -linet6" >&5 +ac_lib_var=`echo inet6'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-linet6 $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo inet6 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + +echo $ac_n "checking for crypt""... $ac_c" 1>&6 +echo "configure:1624: checking for crypt" >&5 +if eval "test \"`echo '$''{'ac_cv_func_crypt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_crypt) || defined (__stub___crypt) +choke me +#else +crypt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1652: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_crypt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_crypt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'crypt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 +echo "configure:1670: checking for crypt in -lcrypt" >&5 +ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrypt $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/^a-zA-Z0-9_/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + +fi + +echo $ac_n "checking for hstrerror""... $ac_c" 1>&6 +echo "configure:1719: checking for hstrerror" >&5 +if eval "test \"`echo '$''{'ac_cv_func_hstrerror'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char hstrerror(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_hstrerror) || defined (__stub___hstrerror) +choke me +#else +hstrerror(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_hstrerror=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_hstrerror=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'hstrerror`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for hstrerror in -lresolv""... $ac_c" 1>&6 +echo "configure:1765: checking for hstrerror in -lresolv" >&5 +ac_lib_var=`echo resolv'_'hstrerror | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lresolv $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + V_NETLIBS="-lresolv $V_NETLIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi + + +for ac_func in strerror +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1810: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" +fi +done + + +for ac_func in waitpid vsnprintf daemon setsid setlogin getaddrinfo getnameinfo gai_strerror kqueue sigset atoll +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1867: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1895: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in unistd.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1923: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1933: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_func in getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1962: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +echo "configure:2015: checking for working mmap" >&5 +if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat > conftest.$ac_ext < +#include +#include + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include +# endif + +/* Assume that all systems that can run configure have sys/param.h. */ +# ifndef HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +#ifdef __cplusplus +extern "C" { void *malloc(unsigned); } +#else +char *malloc(); +#endif + +int +main() +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize(); + + /* + * First, make a file with some known garbage in it. + */ + data = malloc(pagesize); + if (!data) + exit(1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand(); + umask(0); + fd = creat("conftestmmap", 0600); + if (fd < 0) + exit(1); + if (write(fd, data, pagesize) != pagesize) + exit(1); + close(fd); + + /* + * Next, try to mmap the file at a fixed address which + * already has something else allocated at it. If we can, + * also make sure that we see the same garbage. + */ + fd = open("conftestmmap", O_RDWR); + if (fd < 0) + exit(1); + data2 = malloc(2 * pagesize); + if (!data2) + exit(1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit(1); + + /* + * Finally, make sure that changes to the mapped area + * do not percolate back to the file as seen by read(). + * (This is a bug on some variants of i386 svr4.0.) + */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = malloc(pagesize); + if (!data3) + exit(1); + if (read(fd, data3, pagesize) != pagesize) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit(1); + close(fd); + unlink("conftestmmap"); + exit(0); +} + +EOF +if { (eval echo configure:2163: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_mmap_fixed_mapped=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + + +case "$target_os" in +solaris*) + for ac_func in poll +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2191: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2219: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + ;; +*) + for ac_func in select poll +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2248: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2276: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + ;; +esac + +echo $ac_n "checking if struct tm has tm_gmtoff member""... $ac_c" 1>&6 +echo "configure:2304: checking if struct tm has tm_gmtoff member" >&5 + if eval "test \"`echo '$''{'ac_cv_acme_tm_has_tm_gmtoff'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# include +int main() { +u_int i = sizeof(((struct tm *)0)->tm_gmtoff) +; return 0; } +EOF +if { (eval echo configure:2318: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_acme_tm_has_tm_gmtoff=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_acme_tm_has_tm_gmtoff=no +fi +rm -f conftest* +fi + + echo "$ac_t""$ac_cv_acme_tm_has_tm_gmtoff" 1>&6 + if test $ac_cv_acme_tm_has_tm_gmtoff = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_TM_GMTOFF 1 +EOF + + fi +echo $ac_n "checking if int64_t exists""... $ac_c" 1>&6 +echo "configure:2338: checking if int64_t exists" >&5 + if eval "test \"`echo '$''{'ac_cv_acme_int64_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +int64_t i64 +; return 0; } +EOF +if { (eval echo configure:2351: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_acme_int64_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_acme_int64_t=no +fi +rm -f conftest* +fi + + echo "$ac_t""$ac_cv_acme_int64_t" 1>&6 + if test $ac_cv_acme_int64_t = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_INT64T 1 +EOF + + fi +echo $ac_n "checking if socklen_t exists""... $ac_c" 1>&6 +echo "configure:2371: checking if socklen_t exists" >&5 + if eval "test \"`echo '$''{'ac_cv_acme_socklen_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# include +int main() { +socklen_t slen +; return 0; } +EOF +if { (eval echo configure:2385: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_acme_socklen_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_acme_socklen_t=no +fi +rm -f conftest* +fi + + echo "$ac_t""$ac_cv_acme_socklen_t" 1>&6 + if test $ac_cv_acme_socklen_t = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLENT 1 +EOF + + fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:2406: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:2444: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + + + + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile cgi-src/Makefile extras/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@LIBOBJS@%$LIBOBJS%g +s%@SET_MAKE@%$SET_MAKE%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@V_CCOPT@%$V_CCOPT%g +s%@V_STATICFLAG@%$V_STATICFLAG%g +s%@V_NETLIBS@%$V_NETLIBS%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/src/thttpd-2.27/configure.in b/src/thttpd-2.27/configure.in new file mode 100644 index 0000000..1209ddc --- /dev/null +++ b/src/thttpd-2.27/configure.in @@ -0,0 +1,138 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(thttpd.c) + +AC_CANONICAL_SYSTEM + +AC_PROG_CC + +V_CCOPT="-O" +if test "$GCC" = yes ; then + AC_MSG_CHECKING(gcc version) + AC_CACHE_VAL(ac_cv_lbl_gcc_vers, + ac_cv_lbl_gcc_vers=`$CC -dumpversion 2>&1 | \ + sed -e 's/\..*//'`) + AC_MSG_RESULT($ac_cv_lbl_gcc_vers) + if test "$ac_cv_lbl_gcc_vers" -gt 1 ; then + V_CCOPT="-O2" + fi +fi +if test -f .devel ; then + V_CCOPT="-g $V_CCOPT -ansi -pedantic -U__STRICT_ANSI__ -Wall -Wpointer-arith -Wshadow -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wno-long-long" +fi + +dnl +dnl maybe this should be a loop +dnl +AC_MSG_CHECKING(how to link static binaries) +AC_CACHE_VAL(ac_cv_lbl_static_flag, + ac_cv_lbl_static_flag=unknown + echo 'main() {}' > conftest.c + if test "$GCC" != yes ; then + trial_flag="-Bstatic" + test=`$CC $trial_flag -o conftest conftest.c 2>&1` + if test -z "$test" ; then + ac_cv_lbl_static_flag="$trial_flag" + fi + rm -f conftest + fi + if test "$ac_cv_lbl_static_flag" = unknown ; then + trial_flag="-static" + test=`$CC $trial_flag -o conftest conftest.c 2>&1` + if test -z "$test" ; then + ac_cv_lbl_static_flag="$trial_flag" + fi + rm -f conftest + fi + rm conftest.c) +AC_MSG_RESULT($ac_cv_lbl_static_flag) +if test "$ac_cv_lbl_static_flag" != unknown ; then + V_STATICFLAG="$ac_cv_lbl_static_flag" +fi + +AC_MSG_CHECKING(for __progname) +AC_CACHE_VAL(ac_cv_extern__progname, + AC_TRY_LINK([], + [extern char *__progname; + puts(__progname)], + ac_cv_extern__progname=yes, + ac_cv_extern__progname=no)) +if test $ac_cv_extern__progname = yes ; then + AC_DEFINE(HAVE__PROGNAME) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/devpoll.h sys/event.h osreldate.h) +AC_HEADER_TIME +AC_HEADER_DIRENT + +d="/usr/local/v6/lib" +AC_MSG_CHECKING(for $d) +if test -d $d; then + AC_MSG_RESULT(yes (Adding -L$d to LDFLAGS)) + LDFLAGS="$LDFLAGS -L$d" +else + AC_MSG_RESULT(no) +fi + +dnl +dnl Most operating systems have gethostbyname() in the default searched +dnl libraries (i.e. libc): +dnl +V_NETLIBS="" +AC_CHECK_FUNC(gethostbyname, , + # Some OSes (eg. Solaris) place it in libnsl: + AC_LBL_CHECK_LIB(nsl, gethostbyname, + V_NETLIBS="-lnsl $V_NETLIBS", + # Some strange OSes (SINIX) have it in libsocket: + AC_LBL_CHECK_LIB(socket, gethostbyname, + V_NETLIBS="-lsocket $V_NETLIBS", + # Unfortunately libsocket sometimes depends on libnsl. + # AC_CHECK_LIB's API is essentially broken so the + # following ugliness is necessary: + AC_LBL_CHECK_LIB(socket, gethostbyname, + V_NETLIBS="-lsocket -lnsl $V_NETLIBS", + AC_CHECK_LIB(resolv, gethostbyname, + V_NETLIBS="-lresolv $V_NETLIBS"), + -lnsl)))) +AC_CHECK_FUNC(socket, , + AC_CHECK_LIB(socket, socket, + V_NETLIBS="-lsocket $V_NETLIBS", + AC_LBL_CHECK_LIB(socket, socket, + V_NETLIBS="-lsocket -lnsl $V_NETLIBS", , -lnsl))) + +AC_CHECK_LIB(inet6, main) + +AC_CHECK_FUNC(crypt, , AC_CHECK_LIB(crypt, crypt)) +AC_CHECK_FUNC(hstrerror, , + AC_CHECK_LIB(resolv, hstrerror, V_NETLIBS="-lresolv $V_NETLIBS")) + +AC_REPLACE_FUNCS(strerror) +AC_CHECK_FUNCS(waitpid vsnprintf daemon setsid setlogin getaddrinfo getnameinfo gai_strerror kqueue sigset atoll) +AC_FUNC_MMAP + +case "$target_os" in +solaris*) + dnl Solaris's select() is a bad wrapper routine. + AC_CHECK_FUNCS(poll) + ;; +*) + AC_CHECK_FUNCS(select poll) + ;; +esac + +AC_ACME_TM_GMTOFF +AC_ACME_INT64T +AC_ACME_SOCKLENT + +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +AC_SUBST(DEFS) +AC_SUBST(V_CCOPT) +AC_SUBST(V_STATICFLAG) +AC_SUBST(V_NETLIBS) + +AC_OUTPUT(Makefile cgi-src/Makefile extras/Makefile) diff --git a/src/thttpd-2.27/contrib/redhat-rpm/thttpd.conf b/src/thttpd-2.27/contrib/redhat-rpm/thttpd.conf new file mode 100644 index 0000000..02fce15 --- /dev/null +++ b/src/thttpd-2.27/contrib/redhat-rpm/thttpd.conf @@ -0,0 +1,14 @@ +# This section overrides defaults +dir=/home/httpd/html +chroot +user=httpd# default = nobody +logfile=/var/log/thttpd.log +pidfile=/var/run/thttpd.pid +# This section _documents_ defaults in effect +# port=80 +# nosymlink# default = !chroot +# novhost +# nocgipat +# nothrottles +# host=0.0.0.0 +# charset=iso-8859-1 diff --git a/src/thttpd-2.27/contrib/redhat-rpm/thttpd.init b/src/thttpd-2.27/contrib/redhat-rpm/thttpd.init new file mode 100755 index 0000000..58e3aba --- /dev/null +++ b/src/thttpd-2.27/contrib/redhat-rpm/thttpd.init @@ -0,0 +1,47 @@ +#!/bin/bash +# The following two lines enable chkconfig(1) to manipulate this script +# chkconfig: 2345 99 01 +# description: control Jef Poskanzer's tiny/turbo/throttling http daemon + +# source function library +. /etc/rc.d/init.d/functions + +pidfile=/var/run/thttpd.pid +pid=`cat $pidfile 2>/dev/null` + +if test -n "$pid" && kill -0 $pid 2>/dev/null; then + dead=no +else + dead=yes +fi + +die(){ + echo -n "$*"; echo_failure; echo '' + exit 1; +} + +case "$1" in + start) test "$dead" = yes || die thttpd is already running + echo -n "Starting thttpd: " + daemon /usr/sbin/thttpd -C /etc/thttpd.conf + touch /var/lock/subsys/thttpd + echo_success;echo '' + exit 0 + ;; + stop) echo -n "Gently shutting down thttpd: " + signal=USR1 + ;; + kill) echo -n "Violently killing thttpd: " + signal=INT + ;; +status) status thttpd; exit $?;; +restart) $0 stop; sleep 2; exec $0 start;; + *) die "Usage: thttpd {start|stop|restart|status}";; +esac + +test "$dead" = no || die thttpd is not running +kill -$signal $pid +sleep 2 +kill -0 $pid 2>/dev/null && die "thttpd[$pid] will not die" +rm -f /var/lock/subsys/thttpd +echo_success; echo '' diff --git a/src/thttpd-2.27/contrib/redhat-rpm/thttpd.spec b/src/thttpd-2.27/contrib/redhat-rpm/thttpd.spec new file mode 100644 index 0000000..056a846 --- /dev/null +++ b/src/thttpd-2.27/contrib/redhat-rpm/thttpd.spec @@ -0,0 +1,154 @@ +Summary: Throttleable lightweight httpd server +Name: thttpd +Version: 2.27 +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 + - Updated to 2.26 + +* Sat Dec 20 2003 Jef Poskanzer + - Updated to 2.25b + +* Mon Oct 27 2003 Jef Poskanzer + - Updated to 2.25 + +* Sat Sep 13 2003 Jef Poskanzer + - Updated to 2.24 + +* Sat May 25 2002 Jef Poskanzer + - Updated to 2.23 + +* Mon Jul 09 2001 Jef Poskanzer + - Updated to 2.22 + +* Thu Apr 26 2001 Jef Poskanzer + - Updated to 2.21c + +* Mon Apr 23 2001 Jef Poskanzer + - Updated to 2.21b + +* Mon Oct 02 2000 Jef Poskanzer + - Updated to 2.21 + +* Wed Sep 13 2000 Jef Poskanzer + - Updated to 2.20 + +* Mon Sep 11 2000 Bennett Todd + - added thttpd.conf, took config info out of init script + - switched to logging in /var/log, used pidfile + +* Thu Jun 15 2000 Jef Poskanzer + - Updated to 2.19 + +* Thu May 18 2000 Jef Poskanzer + - Updated to 2.18 + +* Fri Mar 17 2000 Jef Poskanzer + - Updated to 2.17 + +* Mon Feb 28 2000 Jef Poskanzer + - Updated to 2.16 + +* Thu Feb 03 2000 Jef Poskanzer + - Updated to 2.15 + +* Thu Jan 21 2000 Jef Poskanzer + - Updated to 2.14 + +* Thu Jan 6 2000 Jef Poskanzer + - Updated to 2.13 + +* Mon Jan 3 2000 Bennett Todd + - updated to 2.12, tweaked to move thttpd.init into tarball + +* Mon Dec 13 1999 Bennett Todd + - Updated to 2.09 + +* Fri Dec 10 1999 Bennett Todd + - Updated to 2.08 + +* Wed Nov 24 1999 Bennett Todd + - updated to 2.06, parameterized Version string in source url + - changed to use "make install", simplified %files list + +* Wed Nov 10 1999 Bennett Todd + - Version 2.05, reset release to 1 + - dropped bugfix patch since Jef included that + - streamlined install + +* Sun Jul 25 1999 Bennett Todd + - Release 4, added mime type swf + +* Mon May 3 1999 Bennett Todd + - Release 2, added patch to set cgi-timelimit up to 10 minutes + fm default 30 seconds + +* Wed Feb 10 1999 Bennett Todd + - based on 2.00-2, bumped to 2.04, reset release back to 1 + - fixed a couple of broken entries in %install to reference $RPM_BUILD_ROOT + - simplified %files to populate /usr/doc/... with just [A-Z]* (TODO had gone + away, this simplification makes it liklier to be trivially portable to + future releases). + - added %doc tags for the man pages + diff --git a/src/thttpd-2.27/extras/Makefile b/src/thttpd-2.27/extras/Makefile new file mode 100644 index 0000000..b7ae354 --- /dev/null +++ b/src/thttpd-2.27/extras/Makefile @@ -0,0 +1,87 @@ +# Generated automatically from Makefile.in by configure. +# Makefile for extras. +# +# Copyright © 1995,1998 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +prefix = /usr/local +exec_prefix = ${prefix} +BINDIR = ${exec_prefix}/sbin +WEBDIR = $(prefix)/www +CGIBINDIR = $(WEBDIR)/cgi-bin +MANDIR = ${prefix}/man + +CC = gcc +CCOPT = -O2 +DEFS = -DHAVE__PROGNAME=1 -DHAVE_FCNTL_H=1 -DHAVE_GRP_H=1 -DHAVE_MEMORY_H=1 -DHAVE_PATHS_H=1 -DHAVE_POLL_H=1 -DHAVE_SYS_POLL_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_DIRENT_H=1 -DHAVE_LIBCRYPT=1 -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_VSNPRINTF=1 -DHAVE_DAEMON=1 -DHAVE_SETSID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_SIGSET=1 -DHAVE_ATOLL=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DHAVE_SELECT=1 -DHAVE_POLL=1 -DHAVE_TM_GMTOFF=1 -DHAVE_INT64T=1 -DHAVE_SOCKLENT=1 +INCLS = -I.. +CFLAGS = $(CCOPT) $(DEFS) $(INCLS) +STATICFLAG = +LDFLAGS = +LIBS = -lcrypt +NETLIBS = +INSTALL = /usr/bin/install -c + +CLEANFILES = *.o makeweb htpasswd + + + +.c.o: + @rm -f $@ + $(CC) $(CFLAGS) -c $*.c + +all: makeweb htpasswd + +makeweb: makeweb.o + $(CC) $(LDFLAGS) makeweb.o -o makeweb $(LIBS) $(NETLIBS) + +makeweb.o: makeweb.c ../config.h + $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c makeweb.c + +htpasswd: htpasswd.o + $(CC) $(LDFLAGS) $(STATICFLAG) htpasswd.o -o htpasswd $(LIBS) + +htpasswd.o: htpasswd.c ../config.h + $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c htpasswd.c + + +install: all + rm -f $(BINDIR)/makeweb $(BINDIR)/htpasswd $(BINDIR)/syslogtocern + cp makeweb $(BINDIR)/makeweb + chgrp $(WEBGROUP) $(BINDIR)/makeweb + chmod 2755 $(BINDIR)/makeweb + cp htpasswd $(BINDIR)/htpasswd + cp syslogtocern $(BINDIR)/syslogtocern + rm -f $(MANDIR)/man1/makeweb.1 + cp makeweb.1 $(MANDIR)/man1/makeweb.1 + rm -f $(MANDIR)/man1/htpasswd.1 + cp htpasswd.1 $(MANDIR)/man1/htpasswd.1 + rm -f $(MANDIR)/man8/syslogtocern.8 + cp syslogtocern.8 $(MANDIR)/man8/syslogtocern.8 + +clean: + rm -f $(CLEANFILES) + +distclean: + rm -f $(CLEANFILES) Makefile diff --git a/src/thttpd-2.27/extras/Makefile.in b/src/thttpd-2.27/extras/Makefile.in new file mode 100644 index 0000000..a29780f --- /dev/null +++ b/src/thttpd-2.27/extras/Makefile.in @@ -0,0 +1,86 @@ +# Makefile for extras. +# +# Copyright © 1995,1998 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +BINDIR = @sbindir@ +WEBDIR = $(prefix)/www +CGIBINDIR = $(WEBDIR)/cgi-bin +MANDIR = @mandir@ + +CC = @CC@ +CCOPT = @V_CCOPT@ +DEFS = @DEFS@ +INCLS = -I.. +CFLAGS = $(CCOPT) $(DEFS) $(INCLS) +STATICFLAG = @V_STATICFLAG@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +NETLIBS = @V_NETLIBS@ +INSTALL = @INSTALL@ + +CLEANFILES = *.o makeweb htpasswd + +@SET_MAKE@ + +.c.o: + @rm -f $@ + $(CC) $(CFLAGS) -c $*.c + +all: makeweb htpasswd + +makeweb: makeweb.o + $(CC) $(LDFLAGS) makeweb.o -o makeweb $(LIBS) $(NETLIBS) + +makeweb.o: makeweb.c ../config.h + $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c makeweb.c + +htpasswd: htpasswd.o + $(CC) $(LDFLAGS) $(STATICFLAG) htpasswd.o -o htpasswd $(LIBS) + +htpasswd.o: htpasswd.c ../config.h + $(CC) $(CFLAGS) -DWEBDIR=\"$(WEBDIR)\" -c htpasswd.c + + +install: all + rm -f $(BINDIR)/makeweb $(BINDIR)/htpasswd $(BINDIR)/syslogtocern + cp makeweb $(BINDIR)/makeweb + chgrp $(WEBGROUP) $(BINDIR)/makeweb + chmod 2755 $(BINDIR)/makeweb + cp htpasswd $(BINDIR)/htpasswd + cp syslogtocern $(BINDIR)/syslogtocern + rm -f $(MANDIR)/man1/makeweb.1 + cp makeweb.1 $(MANDIR)/man1/makeweb.1 + rm -f $(MANDIR)/man1/htpasswd.1 + cp htpasswd.1 $(MANDIR)/man1/htpasswd.1 + rm -f $(MANDIR)/man8/syslogtocern.8 + cp syslogtocern.8 $(MANDIR)/man8/syslogtocern.8 + +clean: + rm -f $(CLEANFILES) + +distclean: + rm -f $(CLEANFILES) Makefile diff --git a/src/thttpd-2.27/extras/htpasswd.1 b/src/thttpd-2.27/extras/htpasswd.1 new file mode 100644 index 0000000..1124b02 --- /dev/null +++ b/src/thttpd-2.27/extras/htpasswd.1 @@ -0,0 +1,16 @@ +.TH htpasswd 1 "05 May 1998" +.SH NAME +htpasswd - manipulate HTTP-server password files +.SH SYNOPSIS +.B htpasswd +.RB [ -c ] +.I passwordfile +.I username +.SH DESCRIPTION +.PP +Sets a user's password in an httpd-style password file. +The -c flag creates a new file. +.SH AUTHOR +Rob McCool. +Modified 29aug97 by Jef Poskanzer to accept new password on stdin, +if stdin is a pipe or file. This is necessary for use from CGI. diff --git a/src/thttpd-2.27/extras/htpasswd.c b/src/thttpd-2.27/extras/htpasswd.c new file mode 100644 index 0000000..1c8adf1 --- /dev/null +++ b/src/thttpd-2.27/extras/htpasswd.c @@ -0,0 +1,217 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#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) { + register 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(register char *s, register long v, register 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); + } + strcpy(user,argv[2]); + + found = 0; + while(!(my_getline(line,MAX_STRING_LEN,f))) { + if(found || (line[0] == '#') || (!line[0])) { + putline(tfp,line); + continue; + } + strcpy(l,line); + getword(w,l,':'); + if(strcmp(user,w)) { + putline(tfp,line); + continue; + } + else { + printf("Changing password for user %s\n",user); + add_password(user,tfp); + found = 1; + } + } + if(!found) { + printf("Adding user %s\n",user); + add_password(user,tfp); + } + fclose(f); + fclose(tfp); + sprintf(command,"cp %s %s",temp_template,argv[1]); + system(command); + unlink(temp_template); + exit(0); +} diff --git a/src/thttpd-2.27/extras/makeweb.1 b/src/thttpd-2.27/extras/makeweb.1 new file mode 100644 index 0000000..ff729c9 --- /dev/null +++ b/src/thttpd-2.27/extras/makeweb.1 @@ -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 . +All rights reserved. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. diff --git a/src/thttpd-2.27/extras/makeweb.c b/src/thttpd-2.27/extras/makeweb.c new file mode 100644 index 0000000..aa7b22f --- /dev/null +++ b/src/thttpd-2.27/extras/makeweb.c @@ -0,0 +1,256 @@ +/* makeweb.c - let a user create a web subdirectory +** +** Copyright © 1995 by Jef Poskanzer . +** 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 +#include +#include +#include +#include +#include +#include +#include + + +#define LINK "public_html" + +static char* argv0; + + +static void +check_room( int size, int len ) + { + if ( len > size ) + { + (void) fprintf( stderr, "%s: internal error, out of room\n", argv0 ); + exit( 1 ); + } + } + + +static void +end_with_slash( char* str ) + { + if ( str[strlen( str ) - 1] != '/' ) + (void) strcat( str, "/" ); + } + + +static void +check_dir( char* dirname, uid_t uid, gid_t gid ) + { + struct stat sb; + + /* Check the directory. */ + if ( stat( dirname, &sb ) < 0 ) + { + if ( errno != ENOENT ) + { + perror( dirname ); + exit( 1 ); + } + /* Doesn't exist. Try to make it. */ + if ( mkdir( dirname, 0755 ) < 0 ) + { + if ( errno == ENOENT ) + (void) printf( "\ +Some part of the path %s does not exist.\n\ +This is probably a configuration error.\n", dirname ); + else + perror( dirname ); + exit( 1 ); + } + (void) printf( "Created web directory %s\n", dirname ); + /* Try to change the group of the new dir to the user's group. */ + (void) chown( dirname, -1, gid ); + } + else + { + /* The directory already exists. Well, check that it is in + ** fact a directory. + */ + if ( ! S_ISDIR( sb.st_mode ) ) + { + (void) printf( + "%s already exists but is not a directory!\n", dirname ); + exit( 1 ); + } + if ( sb.st_uid != uid ) + { + (void) printf( + "%s already exists but you don't own it!\n", dirname ); + exit( 1 ); + } + (void) printf( "Web directory %s already existed.\n", dirname ); + } + } + + +int +main( int argc, char** argv ) + { + char* webdir; + char* prefix; + struct passwd* pwd; + char* username; + char* homedir; + char dirname[5000]; + char linkname[5000]; + char linkbuf[5000]; + struct stat sb; + + argv0 = argv[0]; + if ( argc != 1 ) + { + (void) fprintf( stderr, "usage: %s\n", argv0 ); + exit( 1 ); + } + + pwd = getpwuid( getuid() ); + if ( pwd == (struct passwd*) 0 ) + { + (void) fprintf( stderr, "%s: can't find your username\n", argv0 ); + exit( 1 ); + } + username = pwd->pw_name; + homedir = pwd->pw_dir; + +#ifdef TILDE_MAP_2 + + /* All we have to do for the TILDE_MAP_2 case is make sure there's + ** a public_html subdirectory. + */ + check_room( + sizeof(dirname), strlen( homedir ) + strlen( TILDE_MAP_2 ) + 2 ); + (void) strcpy( dirname, homedir ); + end_with_slash( dirname ); + (void) strcat( dirname, TILDE_MAP_2 ); + + check_dir( dirname, pwd->pw_uid, pwd->pw_gid ); + +#else /* TILDE_MAP_2 */ + + /* Gather the pieces. */ + webdir = WEBDIR; +#ifdef TILDE_MAP_1 + prefix = TILDE_MAP_1; +#else /* TILDE_MAP_1 */ + prefix = ""; +#endif /* TILDE_MAP_1 */ + + /* Assemble the directory name. Be paranoid cause we're sgid. */ + check_room( + sizeof(dirname), + strlen( webdir ) + strlen( prefix ) + strlen( username ) + 3 ); + (void) strcpy( dirname, webdir ); + end_with_slash( dirname ); + if ( strlen( prefix ) != 0 ) + { + (void) strcat( dirname, prefix ); + end_with_slash( dirname ); + } + (void) strcat( dirname, username ); + + /* Assemble the link name. */ + check_room( sizeof(linkname), strlen( homedir ) + strlen( LINK ) + 2 ); + (void) strcpy( linkname, homedir ); + end_with_slash( linkname ); + (void) strcat( linkname, LINK ); + + check_dir( dirname, pwd->pw_uid, pwd->pw_gid ); + + /* Check the symlink. */ + try_link_again: ; + if ( lstat( linkname, &sb ) < 0 ) + { + if ( errno != ENOENT ) + { + perror( linkname ); + exit( 1 ); + } + /* Doesn't exist. Try to make it. */ + if ( symlink( dirname, linkname ) < 0 ) + { + if ( errno == ENOENT ) + (void) printf( "\ +Some part of the path %s does not exist.\n\ +This is probably a configuration error.\n", linkname ); + else + perror( linkname ); + exit( 1 ); + } + (void) printf( "Created symbolic link %s\n", linkname ); + } + else + { + /* The link already exists. Well, check that it is in + ** fact a link. + */ + if ( ! S_ISLNK( sb.st_mode ) ) + { + (void) printf( "\ +%s already exists but is not a\n\ +symbolic link! Perhaps you have a real web subdirectory in your\n\ +home dir from a previous web server configuration? You may have\n\ +to rename it, run %s again, and then copy in the old\n\ +contents.\n", linkname, argv0 ); + exit( 1 ); + } + /* Check the existing link's contents. */ + if ( readlink( linkname, linkbuf, sizeof(linkbuf) ) < 0 ) + { + perror( linkname ); + exit( 1 ); + } + if ( strcmp( dirname, linkbuf ) == 0 ) + (void) printf( "Symbolic link %s already existed.\n", linkname ); + else + { + (void) printf( "\ +Symbolic link %s already existed\n\ +but it points to the wrong place! Attempting to remove and\n\ +recreate it.\n", linkname ); + if ( unlink( linkname ) < 0 ) + { + perror( linkname ); + exit( 1 ); + } + goto try_link_again; + } + } +#endif /* TILDE_MAP_2 */ + + exit( 0 ); + } diff --git a/src/thttpd-2.27/extras/syslogtocern b/src/thttpd-2.27/extras/syslogtocern new file mode 100755 index 0000000..d4a6dfa --- /dev/null +++ b/src/thttpd-2.27/extras/syslogtocern @@ -0,0 +1,68 @@ +#!/bin/sh +# +# syslogtocern - convert thttpd syslog entries into CERN Combined Log Format +# +# Copyright © 1995,1998 by Jef Poskanzer . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +if [ $# -lt 1 ] ; then + echo "usage: $0 logfile ..." >&2 + exit 1 +fi + +tmp1=/tmp/stc1.$$ +rm -f $tmp1 + +# Gather up all the thttpd entries. +egrep -h ' thttpd\[' "$@" > $tmp1 + +# Figure out the current year - it's not in syslog's output. Some versions +# of date have the %Y directive to give the full four-digit year, but others +# only have %y. +year=`date +%y` +if [ $year -gt 70 ] ; then + year=19$year +else + year=20$year +fi + +# If the current year isn't the year that the logfile was generated, we need +# to fix it. This will most likely happen once a year, when this script is +# run on January 1st for December 31st's logfile. So, if the current month +# is January and there are December dates in the log file, we subtract one. +# This should cover most cases. +if [ `date +%m` -eq 1 -a `head -1 $tmp1 | awk '{print $1}'` = "Dec" ] ; then + year=`echo $year - 1 | bc` +fi + +# Do access_log. +awk < $tmp1 '{if ( NF >= 15 && $7 == "-" && $12 >= 100 && $12 < 510) print;}' | + sed -e "s,\([A-Z][a-z][a-z]\) \([0-9 ][0-9]\) \([0-9][0-9]:[0-9][0-9]:[0-9][0-9]\) [^ ]* thttpd\[[0-9]*\]: \([^ ]* [^ ]* [^ ]*\) \(.*\),\4 [\2/\1/${year}:\3] \5," -e 's,\[ ,[0,' > access_log + +# Do error_log. +awk < $tmp1 '{if ( ! ( NF >= 15 && $7 == "-" && $12 >= 100 && $12 < 510) ) print;}' | + sed -e "s,\([A-Z][a-z][a-z] [0-9 ][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\) [^ ]* thttpd\[[0-9]*\]: \(.*\),[\1 ${year}] \2," > error_log + +# Done. +rm -f $tmp1 diff --git a/src/thttpd-2.27/extras/syslogtocern.8 b/src/thttpd-2.27/extras/syslogtocern.8 new file mode 100644 index 0000000..351e385 --- /dev/null +++ b/src/thttpd-2.27/extras/syslogtocern.8 @@ -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 . +All rights reserved. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. diff --git a/src/thttpd-2.27/fdwatch.c b/src/thttpd-2.27/fdwatch.c new file mode 100644 index 0000000..2b3de74 --- /dev/null +++ b/src/thttpd-2.27/fdwatch.c @@ -0,0 +1,834 @@ +/* fdwatch.c - fd watcher routines, either select() or poll() +** +** Copyright © 1999,2000 by Jef Poskanzer . +** 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 +#include +#include +#include +#include +#include +#include +#include + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifdef HAVE_POLL_H +#include +#else /* HAVE_POLL_H */ +#ifdef HAVE_SYS_POLL_H +#include +#endif /* HAVE_SYS_POLL_H */ +#endif /* HAVE_POLL_H */ + +#ifdef HAVE_SYS_DEVPOLL_H +#include +#ifndef HAVE_DEVPOLL +#define HAVE_DEVPOLL +#endif /* !HAVE_DEVPOLL */ +#endif /* HAVE_SYS_DEVPOLL_H */ + +#ifdef HAVE_SYS_EVENT_H +#include +#endif /* HAVE_SYS_EVENT_H */ + +#include "fdwatch.h" + +#ifdef HAVE_SELECT +#ifndef FD_SET +#define NFDBITS 32 +#define FD_SETSIZE 32 +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char*)(p), sizeof(*(p))) +#endif /* !FD_SET */ +#endif /* HAVE_SELECT */ + +static int nfiles; +static long nwatches; +static int* fd_rw; +static void** fd_data; +static int nreturned, next_ridx; + +#ifdef HAVE_KQUEUE + +#define WHICH "kevent" +#define INIT( nf ) kqueue_init( nf ) +#define ADD_FD( fd, rw ) kqueue_add_fd( fd, rw ) +#define DEL_FD( fd ) kqueue_del_fd( fd ) +#define WATCH( timeout_msecs ) kqueue_watch( timeout_msecs ) +#define CHECK_FD( fd ) kqueue_check_fd( fd ) +#define GET_FD( ridx ) kqueue_get_fd( ridx ) + +static int kqueue_init( int nf ); +static void kqueue_add_fd( int fd, int rw ); +static void kqueue_del_fd( int fd ); +static int kqueue_watch( long timeout_msecs ); +static int kqueue_check_fd( int fd ); +static int kqueue_get_fd( int ridx ); + +#else /* HAVE_KQUEUE */ +# ifdef HAVE_DEVPOLL + +#define WHICH "devpoll" +#define INIT( nf ) devpoll_init( nf ) +#define ADD_FD( fd, rw ) devpoll_add_fd( fd, rw ) +#define DEL_FD( fd ) devpoll_del_fd( fd ) +#define WATCH( timeout_msecs ) devpoll_watch( timeout_msecs ) +#define CHECK_FD( fd ) devpoll_check_fd( fd ) +#define GET_FD( ridx ) devpoll_get_fd( ridx ) + +static int devpoll_init( int nf ); +static void devpoll_add_fd( int fd, int rw ); +static void devpoll_del_fd( int fd ); +static int devpoll_watch( long timeout_msecs ); +static int devpoll_check_fd( int fd ); +static int devpoll_get_fd( int ridx ); + +# else /* HAVE_DEVPOLL */ +# ifdef HAVE_POLL + +#define WHICH "poll" +#define INIT( nf ) poll_init( nf ) +#define ADD_FD( fd, rw ) poll_add_fd( fd, rw ) +#define DEL_FD( fd ) poll_del_fd( fd ) +#define WATCH( timeout_msecs ) poll_watch( timeout_msecs ) +#define CHECK_FD( fd ) poll_check_fd( fd ) +#define GET_FD( ridx ) poll_get_fd( ridx ) + +static int poll_init( int nf ); +static void poll_add_fd( int fd, int rw ); +static void poll_del_fd( int fd ); +static int poll_watch( long timeout_msecs ); +static int poll_check_fd( int fd ); +static int poll_get_fd( int ridx ); + +# else /* HAVE_POLL */ +# ifdef HAVE_SELECT + +#define WHICH "select" +#define INIT( nf ) select_init( nf ) +#define ADD_FD( fd, rw ) select_add_fd( fd, rw ) +#define DEL_FD( fd ) select_del_fd( fd ) +#define WATCH( timeout_msecs ) select_watch( timeout_msecs ) +#define CHECK_FD( fd ) select_check_fd( fd ) +#define GET_FD( ridx ) select_get_fd( ridx ) + +static int select_init( int nf ); +static void select_add_fd( int fd, int rw ); +static void select_del_fd( int fd ); +static int select_watch( long timeout_msecs ); +static int select_check_fd( int fd ); +static int select_get_fd( int ridx ); + +# endif /* HAVE_SELECT */ +# endif /* HAVE_POLL */ +# endif /* HAVE_DEVPOLL */ +#endif /* HAVE_KQUEUE */ + + +/* Routines. */ + +/* Figure out how many file descriptors the system allows, and +** initialize the fdwatch data structures. Returns -1 on failure. +*/ +int +fdwatch_get_nfiles( void ) + { + int i; +#ifdef RLIMIT_NOFILE + struct rlimit rl; +#endif /* RLIMIT_NOFILE */ + + /* Figure out how many fd's we can have. */ + nfiles = getdtablesize(); +#ifdef RLIMIT_NOFILE + /* If we have getrlimit(), use that, and attempt to raise the limit. */ + if ( getrlimit( RLIMIT_NOFILE, &rl ) == 0 ) + { + nfiles = rl.rlim_cur; + if ( rl.rlim_max == RLIM_INFINITY ) + rl.rlim_cur = 8192; /* arbitrary */ + else if ( rl.rlim_max > rl.rlim_cur ) + rl.rlim_cur = rl.rlim_max; + if ( setrlimit( RLIMIT_NOFILE, &rl ) == 0 ) + nfiles = rl.rlim_cur; + } +#endif /* RLIMIT_NOFILE */ + +#if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) ) + /* If we use select(), then we must limit ourselves to FD_SETSIZE. */ + nfiles = MIN( nfiles, FD_SETSIZE ); +#endif /* HAVE_SELECT && ! ( HAVE_POLL || HAVE_DEVPOLL || HAVE_KQUEUE ) */ + + /* Initialize the fdwatch data structures. */ + nwatches = 0; + fd_rw = (int*) malloc( sizeof(int) * nfiles ); + fd_data = (void**) malloc( sizeof(void*) * nfiles ); + if ( fd_rw == (int*) 0 || fd_data == (void**) 0 ) + return -1; + for ( i = 0; i < nfiles; ++i ) + fd_rw[i] = -1; + if ( INIT( nfiles ) == -1 ) + return -1; + + return nfiles; + } + + +/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */ +void +fdwatch_add_fd( int fd, void* client_data, int rw ) + { + if ( fd < 0 || fd >= nfiles || fd_rw[fd] != -1 ) + { + syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_add_fd!", fd ); + return; + } + ADD_FD( fd, rw ); + fd_rw[fd] = rw; + fd_data[fd] = client_data; + } + + +/* Remove a descriptor from the watch list. */ +void +fdwatch_del_fd( int fd ) + { + if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 ) + { + syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_del_fd!", fd ); + return; + } + DEL_FD( fd ); + fd_rw[fd] = -1; + fd_data[fd] = (void*) 0; + } + +/* Do the watch. Return value is the number of descriptors that are ready, +** or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means +** wait indefinitely. +*/ +int +fdwatch( long timeout_msecs ) + { + ++nwatches; + nreturned = WATCH( timeout_msecs ); + next_ridx = 0; + return nreturned; + } + + +/* Check if a descriptor was ready. */ +int +fdwatch_check_fd( int fd ) + { + if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 ) + { + syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_check_fd!", fd ); + return 0; + } + return CHECK_FD( fd ); + } + + +void* +fdwatch_get_next_client_data( void ) + { + int fd; + + if ( next_ridx >= nreturned ) + return (void*) -1; + fd = GET_FD( next_ridx++ ); + if ( fd < 0 || fd >= nfiles ) + return (void*) 0; + return fd_data[fd]; + } + + +/* Generate debugging statistics syslog message. */ +void +fdwatch_logstats( long secs ) + { + if ( secs > 0 ) + syslog( + LOG_NOTICE, " fdwatch - %ld %ss (%g/sec)", + nwatches, WHICH, (float) nwatches / secs ); + nwatches = 0; + } + + +#ifdef HAVE_KQUEUE + +static int maxkqevents; +static struct kevent* kqevents; +static int nkqevents; +static struct kevent* kqrevents; +static int* kqrfdidx; +static int kq; + + +static int +kqueue_init( int nf ) + { + kq = kqueue(); + if ( kq == -1 ) + return -1; + maxkqevents = nf * 2; + kqevents = (struct kevent*) malloc( sizeof(struct kevent) * maxkqevents ); + kqrevents = (struct kevent*) malloc( sizeof(struct kevent) * nf ); + kqrfdidx = (int*) malloc( sizeof(int) * nf ); + if ( kqevents == (struct kevent*) 0 || kqrevents == (struct kevent*) 0 || + kqrfdidx == (int*) 0 ) + return -1; + (void) memset( kqevents, 0, sizeof(struct kevent) * maxkqevents ); + (void) memset( kqrfdidx, 0, sizeof(int) * nf ); + return 0; + } + + +static void +kqueue_add_fd( int fd, int rw ) + { + if ( nkqevents >= maxkqevents ) + { + syslog( LOG_ERR, "too many kqevents in kqueue_add_fd!" ); + return; + } + kqevents[nkqevents].ident = fd; + kqevents[nkqevents].flags = EV_ADD; + switch ( rw ) + { + case FDW_READ: kqevents[nkqevents].filter = EVFILT_READ; break; + case FDW_WRITE: kqevents[nkqevents].filter = EVFILT_WRITE; break; + default: break; + } + ++nkqevents; + } + + +static void +kqueue_del_fd( int fd ) + { + if ( nkqevents >= maxkqevents ) + { + syslog( LOG_ERR, "too many kqevents in kqueue_del_fd!" ); + return; + } + kqevents[nkqevents].ident = fd; + kqevents[nkqevents].flags = EV_DELETE; + switch ( fd_rw[fd] ) + { + case FDW_READ: kqevents[nkqevents].filter = EVFILT_READ; break; + case FDW_WRITE: kqevents[nkqevents].filter = EVFILT_WRITE; break; + } + ++nkqevents; + } + + +static int +kqueue_watch( long timeout_msecs ) + { + int i, r; + + if ( timeout_msecs == INFTIM ) + r = kevent( + kq, kqevents, nkqevents, kqrevents, nfiles, (struct timespec*) 0 ); + else + { + struct timespec ts; + ts.tv_sec = timeout_msecs / 1000L; + ts.tv_nsec = ( timeout_msecs % 1000L ) * 1000000L; + r = kevent( kq, kqevents, nkqevents, kqrevents, nfiles, &ts ); + } + nkqevents = 0; + if ( r == -1 ) + return -1; + + for ( i = 0; i < r; ++i ) + kqrfdidx[kqrevents[i].ident] = i; + + return r; + } + + +static int +kqueue_check_fd( int fd ) + { + int ridx = kqrfdidx[fd]; + + if ( ridx < 0 || ridx >= nfiles ) + { + syslog( LOG_ERR, "bad ridx (%d) in kqueue_check_fd!", ridx ); + return 0; + } + if ( ridx >= nreturned ) + return 0; + if ( kqrevents[ridx].ident != fd ) + return 0; + if ( kqrevents[ridx].flags & EV_ERROR ) + return 0; + switch ( fd_rw[fd] ) + { + case FDW_READ: return kqrevents[ridx].filter == EVFILT_READ; + case FDW_WRITE: return kqrevents[ridx].filter == EVFILT_WRITE; + default: return 0; + } + } + + +static int +kqueue_get_fd( int ridx ) + { + if ( ridx < 0 || ridx >= nfiles ) + { + syslog( LOG_ERR, "bad ridx (%d) in kqueue_get_fd!", ridx ); + return -1; + } + return kqrevents[ridx].ident; + } + +#else /* HAVE_KQUEUE */ + + +# ifdef HAVE_DEVPOLL + +static int maxdpevents; +static struct pollfd* dpevents; +static int ndpevents; +static struct pollfd* dprevents; +static int* dp_rfdidx; +static int dp; + + +static int +devpoll_init( int nf ) + { + dp = open( "/dev/poll", O_RDWR ); + if ( dp == -1 ) + return -1; + (void) fcntl( dp, F_SETFD, 1 ); + maxdpevents = nf * 2; + dpevents = (struct pollfd*) malloc( sizeof(struct pollfd) * maxdpevents ); + dprevents = (struct pollfd*) malloc( sizeof(struct pollfd) * nf ); + dp_rfdidx = (int*) malloc( sizeof(int) * nf ); + if ( dpevents == (struct pollfd*) 0 || dprevents == (struct pollfd*) 0 || + dp_rfdidx == (int*) 0 ) + return -1; + (void) memset( dp_rfdidx, 0, sizeof(int) * nf ); + return 0; + } + + +static void +devpoll_add_fd( int fd, int rw ) + { + if ( ndpevents >= maxdpevents ) + { + syslog( LOG_ERR, "too many fds in devpoll_add_fd!" ); + return; + } + dpevents[ndpevents].fd = fd; + switch ( rw ) + { + case FDW_READ: dpevents[ndpevents].events = POLLIN; break; + case FDW_WRITE: dpevents[ndpevents].events = POLLOUT; break; + default: break; + } + ++ndpevents; + } + + +static void +devpoll_del_fd( int fd ) + { + if ( ndpevents >= maxdpevents ) + { + syslog( LOG_ERR, "too many fds in devpoll_del_fd!" ); + return; + } + dpevents[ndpevents].fd = fd; + dpevents[ndpevents].events = POLLREMOVE; + ++ndpevents; + } + + +static int +devpoll_watch( long timeout_msecs ) + { + int i, r; + struct dvpoll dvp; + + r = sizeof(struct pollfd) * ndpevents; + if ( r > 0 && write( dp, dpevents, r ) != r ) + return -1; + + ndpevents = 0; + dvp.dp_fds = dprevents; + dvp.dp_nfds = nfiles; + dvp.dp_timeout = (int) timeout_msecs; + + r = ioctl( dp, DP_POLL, &dvp ); + if ( r == -1 ) + return -1; + + for ( i = 0; i < r; ++i ) + dp_rfdidx[dprevents[i].fd] = i; + + return r; + } + + +static int +devpoll_check_fd( int fd ) + { + int ridx = dp_rfdidx[fd]; + + if ( ridx < 0 || ridx >= nfiles ) + { + syslog( LOG_ERR, "bad ridx (%d) in devpoll_check_fd!", ridx ); + return 0; + } + if ( ridx >= nreturned ) + return 0; + if ( dprevents[ridx].fd != fd ) + return 0; + if ( dprevents[ridx].revents & POLLERR ) + return 0; + switch ( fd_rw[fd] ) + { + case FDW_READ: return dprevents[ridx].revents & ( POLLIN | POLLHUP | POLLNVAL ); + case FDW_WRITE: return dprevents[ridx].revents & ( POLLOUT | POLLHUP | POLLNVAL ); + default: return 0; + } + } + + +static int +devpoll_get_fd( int ridx ) + { + if ( ridx < 0 || ridx >= nfiles ) + { + syslog( LOG_ERR, "bad ridx (%d) in devpoll_get_fd!", ridx ); + return -1; + } + return dprevents[ridx].fd; + } + + +# else /* HAVE_DEVPOLL */ + + +# ifdef HAVE_POLL + +static struct pollfd* pollfds; +static int npoll_fds; +static int* poll_fdidx; +static int* poll_rfdidx; + + +static int +poll_init( int nf ) + { + int i; + + pollfds = (struct pollfd*) malloc( sizeof(struct pollfd) * nf ); + poll_fdidx = (int*) malloc( sizeof(int) * nf ); + poll_rfdidx = (int*) malloc( sizeof(int) * nf ); + if ( pollfds == (struct pollfd*) 0 || poll_fdidx == (int*) 0 || + poll_rfdidx == (int*) 0 ) + return -1; + for ( i = 0; i < nf; ++i ) + pollfds[i].fd = poll_fdidx[i] = -1; + return 0; + } + + +static void +poll_add_fd( int fd, int rw ) + { + if ( npoll_fds >= nfiles ) + { + syslog( LOG_ERR, "too many fds in poll_add_fd!" ); + return; + } + pollfds[npoll_fds].fd = fd; + switch ( rw ) + { + case FDW_READ: pollfds[npoll_fds].events = POLLIN; break; + case FDW_WRITE: pollfds[npoll_fds].events = POLLOUT; break; + default: break; + } + poll_fdidx[fd] = npoll_fds; + ++npoll_fds; + } + + +static void +poll_del_fd( int fd ) + { + int idx = poll_fdidx[fd]; + + if ( idx < 0 || idx >= nfiles ) + { + syslog( LOG_ERR, "bad idx (%d) in poll_del_fd!", idx ); + return; + } + --npoll_fds; + pollfds[idx] = pollfds[npoll_fds]; + poll_fdidx[pollfds[idx].fd] = idx; + pollfds[npoll_fds].fd = -1; + poll_fdidx[fd] = -1; + } + + +static int +poll_watch( long timeout_msecs ) + { + int r, ridx, i; + + r = poll( pollfds, npoll_fds, (int) timeout_msecs ); + if ( r <= 0 ) + return r; + + ridx = 0; + for ( i = 0; i < npoll_fds; ++i ) + if ( pollfds[i].revents & + ( POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL ) ) + { + poll_rfdidx[ridx++] = pollfds[i].fd; + if ( ridx == r ) + break; + } + + return ridx; /* should be equal to r */ + } + + +static int +poll_check_fd( int fd ) + { + int fdidx = poll_fdidx[fd]; + + if ( fdidx < 0 || fdidx >= nfiles ) + { + syslog( LOG_ERR, "bad fdidx (%d) in poll_check_fd!", fdidx ); + return 0; + } + if ( pollfds[fdidx].revents & POLLERR ) + return 0; + switch ( fd_rw[fd] ) + { + case FDW_READ: return pollfds[fdidx].revents & ( POLLIN | POLLHUP | POLLNVAL ); + case FDW_WRITE: return pollfds[fdidx].revents & ( POLLOUT | POLLHUP | POLLNVAL ); + default: return 0; + } + } + + +static int +poll_get_fd( int ridx ) + { + if ( ridx < 0 || ridx >= nfiles ) + { + syslog( LOG_ERR, "bad ridx (%d) in poll_get_fd!", ridx ); + return -1; + } + return poll_rfdidx[ridx]; + } + +# else /* HAVE_POLL */ + + +# ifdef HAVE_SELECT + +static fd_set master_rfdset; +static fd_set master_wfdset; +static fd_set working_rfdset; +static fd_set working_wfdset; +static int* select_fds; +static int* select_fdidx; +static int* select_rfdidx; +static int nselect_fds; +static int maxfd; +static int maxfd_changed; + + +static int +select_init( int nf ) + { + int i; + + FD_ZERO( &master_rfdset ); + FD_ZERO( &master_wfdset ); + select_fds = (int*) malloc( sizeof(int) * nf ); + select_fdidx = (int*) malloc( sizeof(int) * nf ); + select_rfdidx = (int*) malloc( sizeof(int) * nf ); + if ( select_fds == (int*) 0 || select_fdidx == (int*) 0 || + select_rfdidx == (int*) 0 ) + return -1; + nselect_fds = 0; + maxfd = -1; + maxfd_changed = 0; + for ( i = 0; i < nf; ++i ) + select_fds[i] = select_fdidx[i] = -1; + return 0; + } + + +static void +select_add_fd( int fd, int rw ) + { + if ( nselect_fds >= nfiles ) + { + syslog( LOG_ERR, "too many fds in select_add_fd!" ); + return; + } + select_fds[nselect_fds] = fd; + switch ( rw ) + { + case FDW_READ: FD_SET( fd, &master_rfdset ); break; + case FDW_WRITE: FD_SET( fd, &master_wfdset ); break; + default: break; + } + if ( fd > maxfd ) + maxfd = fd; + select_fdidx[fd] = nselect_fds; + ++nselect_fds; + } + + +static void +select_del_fd( int fd ) + { + int idx = select_fdidx[fd]; + + if ( idx < 0 || idx >= nfiles ) + { + syslog( LOG_ERR, "bad idx (%d) in select_del_fd!", idx ); + return; + } + + --nselect_fds; + select_fds[idx] = select_fds[nselect_fds]; + select_fdidx[select_fds[idx]] = idx; + select_fds[nselect_fds] = -1; + select_fdidx[fd] = -1; + + FD_CLR( fd, &master_rfdset ); + FD_CLR( fd, &master_wfdset ); + + if ( fd >= maxfd ) + maxfd_changed = 1; + } + + +static int +select_get_maxfd( void ) + { + if ( maxfd_changed ) + { + int i; + maxfd = -1; + for ( i = 0; i < nselect_fds; ++i ) + if ( select_fds[i] > maxfd ) + maxfd = select_fds[i]; + maxfd_changed = 0; + } + return maxfd; + } + + +static int +select_watch( long timeout_msecs ) + { + int mfd; + int r, idx, ridx; + + working_rfdset = master_rfdset; + working_wfdset = master_wfdset; + mfd = select_get_maxfd(); + if ( timeout_msecs == INFTIM ) + r = select( + mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0, + (struct timeval*) 0 ); + else + { + struct timeval timeout; + timeout.tv_sec = timeout_msecs / 1000L; + timeout.tv_usec = ( timeout_msecs % 1000L ) * 1000L; + r = select( + mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0, &timeout ); + } + if ( r <= 0 ) + return r; + + ridx = 0; + for ( idx = 0; idx < nselect_fds; ++idx ) + if ( select_check_fd( select_fds[idx] ) ) + { + select_rfdidx[ridx++] = select_fds[idx]; + if ( ridx == r ) + break; + } + + return ridx; /* should be equal to r */ + } + + +static int +select_check_fd( int fd ) + { + switch ( fd_rw[fd] ) + { + case FDW_READ: return FD_ISSET( fd, &working_rfdset ); + case FDW_WRITE: return FD_ISSET( fd, &working_wfdset ); + default: return 0; + } + } + + +static int +select_get_fd( int ridx ) + { + if ( ridx < 0 || ridx >= nfiles ) + { + syslog( LOG_ERR, "bad ridx (%d) in select_get_fd!", ridx ); + return -1; + } + return select_rfdidx[ridx]; + } + +# endif /* HAVE_SELECT */ + +# endif /* HAVE_POLL */ + +# endif /* HAVE_DEVPOLL */ + +#endif /* HAVE_KQUEUE */ diff --git a/src/thttpd-2.27/fdwatch.h b/src/thttpd-2.27/fdwatch.h new file mode 100644 index 0000000..96984cd --- /dev/null +++ b/src/thttpd-2.27/fdwatch.h @@ -0,0 +1,85 @@ +/* fdwatch.h - header file for fdwatch package +** +** This package abstracts the use of the select()/poll()/kqueue() +** system calls. The basic function of these calls is to watch a set +** of file descriptors for activity. select() originated in the BSD world, +** while poll() came from SysV land, and their interfaces are somewhat +** different. fdwatch lets you write your code to a single interface, +** with the portability differences hidden inside the package. +** +** Usage is fairly simple. Call fdwatch_get_nfiles() to initialize +** the package and find out how many fine descriptors are available. +** Then each time through your main loop, call fdwatch_clear(), then +** fdwatch_add_fd() for each of the descriptors you want to watch, +** then call fdwatch() to actually perform the watch. After it returns +** you can check which descriptors are ready via fdwatch_check_fd(). +** +** If your descriptor set hasn't changed from the last time through +** the loop, you can skip calling fdwatch_clear() and fdwatch_add_fd() +** to save a little CPU time. +** +** +** Copyright © 1999 by Jef Poskanzer . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#ifndef _FDWATCH_H_ +#define _FDWATCH_H_ + +#define FDW_READ 0 +#define FDW_WRITE 1 + +#ifndef INFTIM +#define INFTIM -1 +#endif /* INFTIM */ + +/* Figure out how many file descriptors the system allows, and +** initialize the fdwatch data structures. Returns -1 on failure. +*/ +int fdwatch_get_nfiles( void ); + +/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */ +void fdwatch_add_fd( int fd, void* client_data, int rw ); + +/* Delete a descriptor from the watch list. */ +void fdwatch_del_fd( int fd ); + +/* Do the watch. Return value is the number of descriptors that are ready, +** or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means +** wait indefinitely. +*/ +int fdwatch( long timeout_msecs ); + +/* Check if a descriptor was ready. */ +int fdwatch_check_fd( int fd ); + +/* Get the client data for the next returned event. Returns -1 when there +** are no more events. +*/ +void* fdwatch_get_next_client_data( void ); + +/* Generate debugging statistics syslog message. */ +void fdwatch_logstats( long secs ); + +#endif /* _FDWATCH_H_ */ diff --git a/src/thttpd-2.27/index.html b/src/thttpd-2.27/index.html new file mode 100644 index 0000000..9131592 --- /dev/null +++ b/src/thttpd-2.27/index.html @@ -0,0 +1,14 @@ + +thttpd is running + + +

thttpd is running

+ +

+Looks like you got it working. Congrats. + +

+Here's a link to the thttpd web pages. + + + diff --git a/src/thttpd-2.27/install-sh b/src/thttpd-2.27/install-sh new file mode 100755 index 0000000..ebc6691 --- /dev/null +++ b/src/thttpd-2.27/install-sh @@ -0,0 +1,250 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/src/thttpd-2.27/libhttpd.c b/src/thttpd-2.27/libhttpd.c new file mode 100644 index 0000000..3814e6a --- /dev/null +++ b/src/thttpd-2.27/libhttpd.c @@ -0,0 +1,4280 @@ +/* libhttpd.c - HTTP protocol library +** +** Copyright © 1995,1998,1999,2000,2001,2015 by +** Jef Poskanzer . All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + + +#include "config.h" +#include "version.h" + +#ifdef SHOW_SERVER_VERSION +#define EXPOSED_SERVER_SOFTWARE SERVER_SOFTWARE +#else /* SHOW_SERVER_VERSION */ +#define EXPOSED_SERVER_SOFTWARE "thttpd" +#endif /* SHOW_SERVER_VERSION */ + +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_MEMORY_H +#include +#endif /* HAVE_MEMORY_H */ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_OSRELDATE_H +#include +#endif /* HAVE_OSRELDATE_H */ + +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#include "libhttpd.h" +#include "mmc.h" +#include "timers.h" +#include "match.h" +#include "tdate_parse.h" + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#ifndef SHUT_WR +#define SHUT_WR 1 +#endif + +#ifndef HAVE_INT64T +typedef long long int64_t; +#endif + +#ifndef HAVE_SOCKLENT +typedef int socklen_t; +#endif + +#ifdef __CYGWIN__ +#define timezone _timezone +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +/* Forwards. */ +static void check_options( void ); +static void free_httpd_server( httpd_server* hs ); +static int initialize_listen_socket( httpd_sockaddr* saP ); +static void add_response( httpd_conn* hc, char* str ); +static void send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, off_t length, time_t mod ); +static void send_response( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg ); +static void send_response_tail( httpd_conn* hc ); +static void defang( char* str, char* dfstr, int dfsize ); +#ifdef ERR_DIR +static int send_err_file( httpd_conn* hc, int status, char* title, char* extraheads, char* filename ); +#endif /* ERR_DIR */ +#ifdef AUTH_FILE +static void send_authenticate( httpd_conn* hc, char* realm ); +static int b64_decode( const char* str, unsigned char* space, int size ); +static int auth_check( httpd_conn* hc, char* dirname ); +static int auth_check2( httpd_conn* hc, char* dirname ); +#endif /* AUTH_FILE */ +static void send_dirredirect( httpd_conn* hc ); +static int hexit( char c ); +static void strdecode( char* to, char* from ); +#ifdef GENERATE_INDEXES +static void strencode( char* to, int tosize, char* from ); +#endif /* GENERATE_INDEXES */ +#ifdef TILDE_MAP_1 +static int tilde_map_1( httpd_conn* hc ); +#endif /* TILDE_MAP_1 */ +#ifdef TILDE_MAP_2 +static int tilde_map_2( httpd_conn* hc ); +#endif /* TILDE_MAP_2 */ +static int vhost_map( httpd_conn* hc ); +static char* expand_symlinks( char* path, char** restP, int no_symlink_check, int tildemapped ); +static char* bufgets( httpd_conn* hc ); +static void de_dotdot( char* file ); +static void init_mime( void ); +static void figure_mime( httpd_conn* hc ); +#ifdef CGI_TIMELIMIT +static void cgi_kill2( ClientData client_data, struct timeval* nowP ); +static void cgi_kill( ClientData client_data, struct timeval* nowP ); +#endif /* CGI_TIMELIMIT */ +#ifdef GENERATE_INDEXES +static int ls( httpd_conn* hc ); +#endif /* GENERATE_INDEXES */ +static char* build_env( char* fmt, char* arg ); +#ifdef SERVER_NAME_LIST +static char* hostname_map( char* hostname ); +#endif /* SERVER_NAME_LIST */ +static char** make_envp( httpd_conn* hc ); +static char** make_argp( httpd_conn* hc ); +static void cgi_interpose_input( httpd_conn* hc, int wfd ); +static void post_post_garbage_hack( httpd_conn* hc ); +static void cgi_interpose_output( httpd_conn* hc, int rfd ); +static void cgi_child( httpd_conn* hc ); +static int cgi( httpd_conn* hc ); +static int really_start_request( httpd_conn* hc, struct timeval* nowP ); +static void make_log_entry( httpd_conn* hc, struct timeval* nowP ); +static int check_referrer( httpd_conn* hc ); +static int really_check_referrer( httpd_conn* hc ); +static int sockaddr_check( httpd_sockaddr* saP ); +static size_t sockaddr_len( httpd_sockaddr* saP ); +static int my_snprintf( char* str, size_t size, const char* format, ... ); +#ifndef HAVE_ATOLL +static long long atoll( const char* str ); +#endif /* HAVE_ATOLL */ + + +/* This global keeps track of whether we are in the main process or a +** sub-process. The reason is that httpd_write_response() can get called +** in either context; when it is called from the main process it must use +** non-blocking I/O to avoid stalling the server, but when it is called +** from a sub-process it wants to use blocking I/O so that the whole +** response definitely gets written. So, it checks this variable. A bit +** of a hack but it seems to do the right thing. +*/ +static int sub_process = 0; + + +static void +check_options( void ) + { +#if defined(TILDE_MAP_1) && defined(TILDE_MAP_2) + syslog( LOG_CRIT, "both TILDE_MAP_1 and TILDE_MAP_2 are defined" ); + exit( 1 ); +#endif /* both */ + } + + +static void +free_httpd_server( httpd_server* hs ) + { + if ( hs->binding_hostname != (char*) 0 ) + free( (void*) hs->binding_hostname ); + if ( hs->cwd != (char*) 0 ) + free( (void*) hs->cwd ); + if ( hs->cgi_pattern != (char*) 0 ) + free( (void*) hs->cgi_pattern ); + if ( hs->charset != (char*) 0 ) + free( (void*) hs->charset ); + if ( hs->p3p != (char*) 0 ) + free( (void*) hs->p3p ); + if ( hs->url_pattern != (char*) 0 ) + free( (void*) hs->url_pattern ); + if ( hs->local_pattern != (char*) 0 ) + free( (void*) hs->local_pattern ); + free( (void*) hs ); + } + + +httpd_server* +httpd_initialize( + char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, + unsigned short port, char* cgi_pattern, int cgi_limit, char* charset, + char* p3p, int max_age, char* cwd, int no_log, FILE* logfp, + int no_symlink_check, int vhost, int global_passwd, char* url_pattern, + char* local_pattern, int no_empty_referrers ) + { + httpd_server* hs; + static char ghnbuf[256]; + char* cp; + + check_options(); + + hs = NEW( httpd_server, 1 ); + if ( hs == (httpd_server*) 0 ) + { + syslog( LOG_CRIT, "out of memory allocating an httpd_server" ); + return (httpd_server*) 0; + } + + if ( hostname != (char*) 0 ) + { + hs->binding_hostname = strdup( hostname ); + if ( hs->binding_hostname == (char*) 0 ) + { + syslog( LOG_CRIT, "out of memory copying hostname" ); + return (httpd_server*) 0; + } + hs->server_hostname = hs->binding_hostname; + } + else + { + hs->binding_hostname = (char*) 0; + hs->server_hostname = (char*) 0; + if ( gethostname( ghnbuf, sizeof(ghnbuf) ) < 0 ) + ghnbuf[0] = '\0'; +#ifdef SERVER_NAME_LIST + if ( ghnbuf[0] != '\0' ) + hs->server_hostname = hostname_map( ghnbuf ); +#endif /* SERVER_NAME_LIST */ + if ( hs->server_hostname == (char*) 0 ) + { +#ifdef SERVER_NAME + hs->server_hostname = SERVER_NAME; +#else /* SERVER_NAME */ + if ( ghnbuf[0] != '\0' ) + hs->server_hostname = ghnbuf; +#endif /* SERVER_NAME */ + } + } + + hs->port = port; + if ( cgi_pattern == (char*) 0 ) + hs->cgi_pattern = (char*) 0; + else + { + /* Nuke any leading slashes. */ + if ( cgi_pattern[0] == '/' ) + ++cgi_pattern; + hs->cgi_pattern = strdup( cgi_pattern ); + if ( hs->cgi_pattern == (char*) 0 ) + { + syslog( LOG_CRIT, "out of memory copying cgi_pattern" ); + return (httpd_server*) 0; + } + /* Nuke any leading slashes in the cgi pattern. */ + while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 ) + (void) ol_strcpy( cp + 1, cp + 2 ); + } + hs->cgi_limit = cgi_limit; + hs->cgi_count = 0; + hs->charset = strdup( charset ); + hs->p3p = strdup( p3p ); + hs->max_age = max_age; + hs->cwd = strdup( cwd ); + if ( hs->cwd == (char*) 0 ) + { + syslog( LOG_CRIT, "out of memory copying cwd" ); + return (httpd_server*) 0; + } + if ( url_pattern == (char*) 0 ) + hs->url_pattern = (char*) 0; + else + { + hs->url_pattern = strdup( url_pattern ); + if ( hs->url_pattern == (char*) 0 ) + { + syslog( LOG_CRIT, "out of memory copying url_pattern" ); + return (httpd_server*) 0; + } + } + if ( local_pattern == (char*) 0 ) + hs->local_pattern = (char*) 0; + else + { + hs->local_pattern = strdup( local_pattern ); + if ( hs->local_pattern == (char*) 0 ) + { + syslog( LOG_CRIT, "out of memory copying local_pattern" ); + return (httpd_server*) 0; + } + } + hs->no_log = no_log; + hs->logfp = (FILE*) 0; + httpd_set_logfp( hs, logfp ); + hs->no_symlink_check = no_symlink_check; + hs->vhost = vhost; + hs->global_passwd = global_passwd; + hs->no_empty_referrers = no_empty_referrers; + + /* Initialize listen sockets. Try v6 first because of a Linux peculiarity; + ** like some other systems, it has magical v6 sockets that also listen for + ** v4, but in Linux if you bind a v4 socket first then the v6 bind fails. + */ + if ( sa6P == (httpd_sockaddr*) 0 ) + hs->listen6_fd = -1; + else + hs->listen6_fd = initialize_listen_socket( sa6P ); + if ( sa4P == (httpd_sockaddr*) 0 ) + hs->listen4_fd = -1; + else + hs->listen4_fd = initialize_listen_socket( sa4P ); + /* If we didn't get any valid sockets, fail. */ + if ( hs->listen4_fd == -1 && hs->listen6_fd == -1 ) + { + free_httpd_server( hs ); + return (httpd_server*) 0; + } + + init_mime(); + + /* Done initializing. */ + if ( hs->binding_hostname == (char*) 0 ) + syslog( + LOG_NOTICE, "%.80s starting on port %d", SERVER_SOFTWARE, + (int) hs->port ); + else + syslog( + LOG_NOTICE, "%.80s starting on %.80s, port %d", SERVER_SOFTWARE, + httpd_ntoa( hs->listen4_fd != -1 ? sa4P : sa6P ), + (int) hs->port ); + return hs; + } + + +static int +initialize_listen_socket( httpd_sockaddr* saP ) + { + int listen_fd; + int on, flags; + + /* Check sockaddr. */ + if ( ! sockaddr_check( saP ) ) + { + syslog( LOG_CRIT, "unknown sockaddr family on listen socket" ); + return -1; + } + + /* Create socket. */ + listen_fd = socket( saP->sa.sa_family, SOCK_STREAM, 0 ); + if ( listen_fd < 0 ) + { + syslog( LOG_CRIT, "socket %.80s - %m", httpd_ntoa( saP ) ); + return -1; + } + (void) fcntl( listen_fd, F_SETFD, 1 ); + + /* Allow reuse of local addresses. */ + on = 1; + if ( setsockopt( + listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &on, + sizeof(on) ) < 0 ) + syslog( LOG_CRIT, "setsockopt SO_REUSEADDR - %m" ); + + /* Bind to it. */ + if ( bind( listen_fd, &saP->sa, sockaddr_len( saP ) ) < 0 ) + { + syslog( + LOG_CRIT, "bind %.80s - %m", httpd_ntoa( saP ) ); + (void) close( listen_fd ); + return -1; + } + + /* Set the listen file descriptor to no-delay / non-blocking mode. */ + flags = fcntl( listen_fd, F_GETFL, 0 ); + if ( flags == -1 ) + { + syslog( LOG_CRIT, "fcntl F_GETFL - %m" ); + (void) close( listen_fd ); + return -1; + } + if ( fcntl( listen_fd, F_SETFL, flags | O_NDELAY ) < 0 ) + { + syslog( LOG_CRIT, "fcntl O_NDELAY - %m" ); + (void) close( listen_fd ); + return -1; + } + + /* Start a listen going. */ + if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 ) + { + syslog( LOG_CRIT, "listen - %m" ); + (void) close( listen_fd ); + return -1; + } + + /* Use accept filtering, if available. */ +#ifdef SO_ACCEPTFILTER + { +#if ( __FreeBSD_version >= 411000 ) +#define ACCEPT_FILTER_NAME "httpready" +#else +#define ACCEPT_FILTER_NAME "dataready" +#endif + struct accept_filter_arg af; + (void) bzero( &af, sizeof(af) ); + (void) strcpy( af.af_name, ACCEPT_FILTER_NAME ); + (void) setsockopt( + listen_fd, SOL_SOCKET, SO_ACCEPTFILTER, (char*) &af, sizeof(af) ); + } +#endif /* SO_ACCEPTFILTER */ + + return listen_fd; + } + + +void +httpd_set_logfp( httpd_server* hs, FILE* logfp ) + { + if ( hs->logfp != (FILE*) 0 ) + (void) fclose( hs->logfp ); + hs->logfp = logfp; + } + + +void +httpd_terminate( httpd_server* hs ) + { + httpd_unlisten( hs ); + if ( hs->logfp != (FILE*) 0 ) + (void) fclose( hs->logfp ); + free_httpd_server( hs ); + } + + +void +httpd_unlisten( httpd_server* hs ) + { + if ( hs->listen4_fd != -1 ) + { + (void) close( hs->listen4_fd ); + hs->listen4_fd = -1; + } + if ( hs->listen6_fd != -1 ) + { + (void) close( hs->listen6_fd ); + hs->listen6_fd = -1; + } + } + + +/* Conditional macro to allow two alternate forms for use in the built-in +** error pages. If EXPLICIT_ERROR_PAGES is defined, the second and more +** explicit error form is used; otherwise, the first and more generic +** form is used. +*/ +#ifdef EXPLICIT_ERROR_PAGES +#define ERROR_FORM(a,b) b +#else /* EXPLICIT_ERROR_PAGES */ +#define ERROR_FORM(a,b) a +#endif /* EXPLICIT_ERROR_PAGES */ + + +static char* ok200title = "OK"; +static char* ok206title = "Partial Content"; + +static char* err302title = "Found"; +static char* err302form = "The actual URL is '%.80s'.\n"; + +static char* err304title = "Not Modified"; + +char* httpd_err400title = "Bad Request"; +char* httpd_err400form = + "Your request has bad syntax or is inherently impossible to satisfy.\n"; + +#ifdef AUTH_FILE +static char* err401title = "Unauthorized"; +static char* err401form = + "Authorization required for the URL '%.80s'.\n"; +#endif /* AUTH_FILE */ + +static char* err403title = "Forbidden"; +#ifndef EXPLICIT_ERROR_PAGES +static char* err403form = + "You do not have permission to get URL '%.80s' from this server.\n"; +#endif /* !EXPLICIT_ERROR_PAGES */ + +static char* err404title = "Not Found"; +static char* err404form = + "The requested URL '%.80s' was not found on this server.\n"; + +char* httpd_err408title = "Request Timeout"; +char* httpd_err408form = + "No request appeared within a reasonable time period.\n"; + +static char* err451title = "Unavailable For Legal Reasons"; +static char* err451form = + "You do not have legal permission to get URL '%.80s' from this server.\n"; + +static char* err500title = "Internal Error"; +static char* err500form = + "There was an unusual problem serving the requested URL '%.80s'.\n"; + +static char* err501title = "Not Implemented"; +static char* err501form = + "The requested method '%.80s' is not implemented by this server.\n"; + +char* httpd_err503title = "Service Temporarily Overloaded"; +char* httpd_err503form = + "The requested URL '%.80s' is temporarily overloaded. Please try again later.\n"; + + +/* Append a string to the buffer waiting to be sent as response. */ +static void +add_response( httpd_conn* hc, char* str ) + { + size_t len; + + len = strlen( str ); + httpd_realloc_str( &hc->response, &hc->maxresponse, hc->responselen + len ); + (void) memmove( &(hc->response[hc->responselen]), str, len ); + hc->responselen += len; + } + +/* Send the buffered response. */ +void +httpd_write_response( httpd_conn* hc ) + { + /* If we are in a sub-process, turn off no-delay mode. */ + if ( sub_process ) + httpd_clear_ndelay( hc->conn_fd ); + /* Send the response, if necessary. */ + if ( hc->responselen > 0 ) + { + (void) httpd_write_fully( hc->conn_fd, hc->response, hc->responselen ); + hc->responselen = 0; + } + } + + +/* Set no-delay / non-blocking mode on a socket. */ +void +httpd_set_ndelay( int fd ) + { + int flags, newflags; + + flags = fcntl( fd, F_GETFL, 0 ); + if ( flags != -1 ) + { + newflags = flags | (int) O_NDELAY; + if ( newflags != flags ) + (void) fcntl( fd, F_SETFL, newflags ); + } + } + + +/* Clear no-delay / non-blocking mode on a socket. */ +void +httpd_clear_ndelay( int fd ) + { + int flags, newflags; + + flags = fcntl( fd, F_GETFL, 0 ); + if ( flags != -1 ) + { + newflags = flags & ~ (int) O_NDELAY; + if ( newflags != flags ) + (void) fcntl( fd, F_SETFL, newflags ); + } + } + + +static void +send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, off_t length, time_t mod ) + { + time_t now, expires; + const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT"; + char nowbuf[100]; + char modbuf[100]; + char expbuf[100]; + char fixed_type[500]; + char buf[1000]; + int partial_content; + int s100; + + hc->status = status; + hc->bytes_to_send = length; + if ( hc->mime_flag ) + { + if ( status == 200 && hc->got_range && + ( hc->last_byte_index >= hc->first_byte_index ) && + ( ( hc->last_byte_index != length - 1 ) || + ( hc->first_byte_index != 0 ) ) && + ( hc->range_if == (time_t) -1 || + hc->range_if == hc->sb.st_mtime ) ) + { + partial_content = 1; + hc->status = status = 206; + title = ok206title; + } + else + { + partial_content = 0; + hc->got_range = 0; + } + + now = time( (time_t*) 0 ); + if ( mod == (time_t) 0 ) + mod = now; + (void) strftime( nowbuf, sizeof(nowbuf), rfc1123fmt, gmtime( &now ) ); + (void) strftime( modbuf, sizeof(modbuf), rfc1123fmt, gmtime( &mod ) ); + (void) my_snprintf( + fixed_type, sizeof(fixed_type), type, hc->hs->charset ); + (void) my_snprintf( buf, sizeof(buf), + "%.20s %d %s\015\012Server: %s\015\012Content-Type: %s\015\012Date: %s\015\012Last-Modified: %s\015\012Accept-Ranges: bytes\015\012Connection: close\015\012", + hc->protocol, status, title, EXPOSED_SERVER_SOFTWARE, fixed_type, + nowbuf, modbuf ); + add_response( hc, buf ); + s100 = status / 100; + if ( s100 != 2 && s100 != 3 ) + { + (void) my_snprintf( buf, sizeof(buf), + "Cache-Control: no-cache,no-store\015\012" ); + add_response( hc, buf ); + } + if ( encodings[0] != '\0' ) + { + (void) my_snprintf( buf, sizeof(buf), + "Content-Encoding: %s\015\012", encodings ); + add_response( hc, buf ); + } + if ( partial_content ) + { + (void) my_snprintf( buf, sizeof(buf), + "Content-Range: bytes %lld-%lld/%lld\015\012Content-Length: %lld\015\012", + (long long) hc->first_byte_index, + (long long) hc->last_byte_index, + (long long) length, + (long long) ( hc->last_byte_index - hc->first_byte_index + 1 ) ); + add_response( hc, buf ); + } + else if ( length >= 0 ) + { + (void) my_snprintf( buf, sizeof(buf), + "Content-Length: %lld\015\012", (long long) length ); + add_response( hc, buf ); + } + if ( hc->hs->p3p[0] != '\0' ) + { + (void) my_snprintf( buf, sizeof(buf), "P3P: %s\015\012", hc->hs->p3p ); + add_response( hc, buf ); + } + if ( hc->hs->max_age >= 0 ) + { + expires = now + hc->hs->max_age; + (void) strftime( + expbuf, sizeof(expbuf), rfc1123fmt, gmtime( &expires ) ); + (void) my_snprintf( buf, sizeof(buf), + "Cache-Control: max-age=%d\015\012Expires: %s\015\012", + hc->hs->max_age, expbuf ); + add_response( hc, buf ); + } + if ( extraheads[0] != '\0' ) + add_response( hc, extraheads ); + add_response( hc, "\015\012" ); + } + } + + +static int str_alloc_count = 0; +static size_t str_alloc_size = 0; + +void +httpd_realloc_str( char** strP, size_t* maxsizeP, size_t size ) + { + if ( *maxsizeP == 0 ) + { + *maxsizeP = MAX( 200, size + 100 ); + *strP = NEW( char, *maxsizeP + 1 ); + ++str_alloc_count; + str_alloc_size += *maxsizeP; + } + else if ( size > *maxsizeP ) + { + str_alloc_size -= *maxsizeP; + *maxsizeP = MAX( *maxsizeP * 2, size * 5 / 4 ); + *strP = RENEW( *strP, char, *maxsizeP + 1 ); + str_alloc_size += *maxsizeP; + } + else + return; + if ( *strP == (char*) 0 ) + { + syslog( + LOG_ERR, "out of memory reallocating a string to %ld bytes", + (long) *maxsizeP ); + exit( 1 ); + } + } + + +static void +send_response( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg ) + { + char defanged_arg[1000], buf[2000]; + + send_mime( + hc, status, title, "", extraheads, "text/html; charset=%s", (off_t) -1, + (time_t) 0 ); + (void) my_snprintf( buf, sizeof(buf), "\ +\n\ +\n\ +\n\ +\n\ + \n\ + \n\ + %d %s\n\ + \n\ +\n\ + \n\ +\n\ +

%d %s

\n", + status, title, status, title ); + add_response( hc, buf ); + defang( arg, defanged_arg, sizeof(defanged_arg) ); + (void) my_snprintf( buf, sizeof(buf), form, defanged_arg ); + add_response( hc, buf ); + if ( match( "**MSIE**", hc->useragent ) ) + { + int n; + add_response( hc, "\n" ); + } + send_response_tail( hc ); + } + + +static void +send_response_tail( httpd_conn* hc ) + { + char buf[1000]; + + (void) my_snprintf( buf, sizeof(buf), "\ +
\n\ +\n\ +
%s
\n\ +\n\ + \n\ +\n\ +\n", + SERVER_ADDRESS, EXPOSED_SERVER_SOFTWARE ); + add_response( hc, buf ); + } + + +static void +defang( char* str, char* dfstr, int dfsize ) + { + char* cp1; + char* cp2; + + for ( cp1 = str, cp2 = dfstr; + *cp1 != '\0' && cp2 - dfstr < dfsize - 5; + ++cp1, ++cp2 ) + { + switch ( *cp1 ) + { + case '<': + *cp2++ = '&'; + *cp2++ = 'l'; + *cp2++ = 't'; + *cp2 = ';'; + break; + case '>': + *cp2++ = '&'; + *cp2++ = 'g'; + *cp2++ = 't'; + *cp2 = ';'; + break; + default: + *cp2 = *cp1; + break; + } + } + *cp2 = '\0'; + } + + +void +httpd_send_err( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg ) + { +#ifdef ERR_DIR + + char filename[1000]; + + /* Try virtual host error page. */ + if ( hc->hs->vhost && hc->hostdir[0] != '\0' ) + { + (void) my_snprintf( filename, sizeof(filename), + "%s/%s/err%d.html", hc->hostdir, ERR_DIR, status ); + if ( send_err_file( hc, status, title, extraheads, filename ) ) + return; + } + + /* Try server-wide error page. */ + (void) my_snprintf( filename, sizeof(filename), + "%s/err%d.html", ERR_DIR, status ); + if ( send_err_file( hc, status, title, extraheads, filename ) ) + return; + + /* Fall back on built-in error page. */ + send_response( hc, status, title, extraheads, form, arg ); + +#else /* ERR_DIR */ + + send_response( hc, status, title, extraheads, form, arg ); + +#endif /* ERR_DIR */ + } + + +#ifdef ERR_DIR +static int +send_err_file( httpd_conn* hc, int status, char* title, char* extraheads, char* filename ) + { + FILE* fp; + char buf[1000]; + size_t r; + + fp = fopen( filename, "r" ); + if ( fp == (FILE*) 0 ) + return 0; + send_mime( + hc, status, title, "", extraheads, "text/html; charset=%s", (off_t) -1, + (time_t) 0 ); + for (;;) + { + r = fread( buf, 1, sizeof(buf) - 1, fp ); + if ( r == 0 ) + break; + buf[r] = '\0'; + add_response( hc, buf ); + } + (void) fclose( fp ); + +#ifdef ERR_APPEND_SERVER_INFO + send_response_tail( hc ); +#endif /* ERR_APPEND_SERVER_INFO */ + + return 1; + } +#endif /* ERR_DIR */ + + +#ifdef AUTH_FILE + +static void +send_authenticate( httpd_conn* hc, char* realm ) + { + static char* header; + static size_t maxheader = 0; + static char headstr[] = "WWW-Authenticate: Basic realm=\""; + + httpd_realloc_str( + &header, &maxheader, sizeof(headstr) + strlen( realm ) + 3 ); + (void) my_snprintf( header, maxheader, "%s%s\"\015\012", headstr, realm ); + httpd_send_err( hc, 401, err401title, header, err401form, hc->encodedurl ); + /* If the request was a POST then there might still be data to be read, + ** so we need to do a lingering close. + */ + if ( hc->method == METHOD_POST ) + hc->should_linger = 1; + } + + +/* Base-64 decoding. This represents binary data as printable ASCII +** characters. Three 8-bit binary bytes are turned into four 6-bit +** values, like so: +** +** [11111111] [22222222] [33333333] +** +** [111111] [112222] [222233] [333333] +** +** Then the 6-bit values are represented using the characters "A-Za-z0-9+/". +*/ + +static int b64_decode_table[256] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ + 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ + 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ + -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ + 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ + }; + +/* Do base-64 decoding on a string. Ignore any non-base64 bytes. +** Return the actual number of bytes generated. The decoded size will +** be at most 3/4 the size of the encoded, and may be smaller if there +** are padding characters (blanks, newlines). +*/ +static int +b64_decode( const char* str, unsigned char* space, int size ) + { + const char* cp; + int space_idx, phase; + int d, prev_d = 0; + unsigned char c; + + space_idx = 0; + phase = 0; + for ( cp = str; *cp != '\0'; ++cp ) + { + d = b64_decode_table[(int) ((unsigned char) *cp)]; + if ( d != -1 ) + { + switch ( phase ) + { + case 0: + ++phase; + break; + case 1: + c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) ); + if ( space_idx < size ) + space[space_idx++] = c; + ++phase; + break; + case 2: + c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) ); + if ( space_idx < size ) + space[space_idx++] = c; + ++phase; + break; + case 3: + c = ( ( ( prev_d & 0x03 ) << 6 ) | d ); + if ( space_idx < size ) + space[space_idx++] = c; + phase = 0; + break; + } + prev_d = d; + } + } + return space_idx; + } + + +/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */ +static int +auth_check( httpd_conn* hc, char* dirname ) + { + if ( hc->hs->global_passwd ) + { + char* topdir; + if ( hc->hs->vhost && hc->hostdir[0] != '\0' ) + topdir = hc->hostdir; + else + topdir = "."; + switch ( auth_check2( hc, topdir ) ) + { + case -1: + return -1; + case 1: + return 1; + } + } + return auth_check2( hc, dirname ); + } + + +/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */ +static int +auth_check2( httpd_conn* hc, char* dirname ) + { + static char* authpath; + static size_t maxauthpath = 0; + struct stat sb; + char authinfo[500]; + char* authpass; + char* colon; + int l; + FILE* fp; + char line[500]; + char* cryp; + static char* prevauthpath; + static size_t maxprevauthpath = 0; + static time_t prevmtime; + static char* prevuser; + static size_t maxprevuser = 0; + static char* prevcryp; + static size_t maxprevcryp = 0; + + /* Construct auth filename. */ + httpd_realloc_str( + &authpath, &maxauthpath, strlen( dirname ) + 1 + sizeof(AUTH_FILE) ); + (void) my_snprintf( authpath, maxauthpath, "%s/%s", dirname, AUTH_FILE ); + + /* Does this directory have an auth file? */ + if ( stat( authpath, &sb ) < 0 ) + /* Nope, let the request go through. */ + return 0; + + /* Does this request contain basic authorization info? */ + if ( hc->authorization[0] == '\0' || + strncmp( hc->authorization, "Basic ", 6 ) != 0 ) + { + /* Nope, return a 401 Unauthorized. */ + send_authenticate( hc, dirname ); + return -1; + } + + /* Decode it. */ + l = b64_decode( + &(hc->authorization[6]), (unsigned char*) authinfo, + sizeof(authinfo) - 1 ); + authinfo[l] = '\0'; + /* Split into user and password. */ + authpass = strchr( authinfo, ':' ); + if ( authpass == (char*) 0 ) + { + /* No colon? Bogus auth info. */ + send_authenticate( hc, dirname ); + return -1; + } + *authpass++ = '\0'; + /* If there are more fields, cut them off. */ + colon = strchr( authpass, ':' ); + if ( colon != (char*) 0 ) + *colon = '\0'; + + /* See if we have a cached entry and can use it. */ + if ( maxprevauthpath != 0 && + strcmp( authpath, prevauthpath ) == 0 && + sb.st_mtime == prevmtime && + strcmp( authinfo, prevuser ) == 0 ) + { + /* Yes. Check against the cached encrypted password. */ + if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 ) + { + /* Ok! */ + httpd_realloc_str( + &hc->remoteuser, &hc->maxremoteuser, strlen( authinfo ) ); + (void) strcpy( hc->remoteuser, authinfo ); + return 1; + } + else + { + /* No. */ + send_authenticate( hc, dirname ); + return -1; + } + } + + /* Open the password file. */ + fp = fopen( authpath, "r" ); + if ( fp == (FILE*) 0 ) + { + /* The file exists but we can't open it? Disallow access. */ + syslog( + LOG_ERR, "%.80s auth file %.80s could not be opened - %m", + httpd_ntoa( &hc->client_addr ), authpath ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' is protected by an authentication file, but the authentication file cannot be opened.\n" ), + hc->encodedurl ); + return -1; + } + + /* Read it. */ + while ( fgets( line, sizeof(line), fp ) != (char*) 0 ) + { + /* Nuke newline. */ + l = strlen( line ); + if ( line[l - 1] == '\n' ) + line[l - 1] = '\0'; + /* Split into user and encrypted password. */ + cryp = strchr( line, ':' ); + if ( cryp == (char*) 0 ) + continue; + *cryp++ = '\0'; + /* Is this the right user? */ + if ( strcmp( line, authinfo ) == 0 ) + { + /* Yes. */ + (void) fclose( fp ); + /* So is the password right? */ + if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 ) + { + /* Ok! */ + httpd_realloc_str( + &hc->remoteuser, &hc->maxremoteuser, strlen( line ) ); + (void) strcpy( hc->remoteuser, line ); + /* And cache this user's info for next time. */ + httpd_realloc_str( + &prevauthpath, &maxprevauthpath, strlen( authpath ) ); + (void) strcpy( prevauthpath, authpath ); + prevmtime = sb.st_mtime; + httpd_realloc_str( + &prevuser, &maxprevuser, strlen( authinfo ) ); + (void) strcpy( prevuser, authinfo ); + httpd_realloc_str( &prevcryp, &maxprevcryp, strlen( cryp ) ); + (void) strcpy( prevcryp, cryp ); + return 1; + } + else + { + /* No. */ + send_authenticate( hc, dirname ); + return -1; + } + } + } + + /* Didn't find that user. Access denied. */ + (void) fclose( fp ); + send_authenticate( hc, dirname ); + return -1; + } + +#endif /* AUTH_FILE */ + + +static void +send_dirredirect( httpd_conn* hc ) + { + static char* location; + static char* header; + static size_t maxlocation = 0, maxheader = 0; + static char headstr[] = "Location: "; + + if ( hc->query[0] != '\0') + { + char* cp = strchr( hc->encodedurl, '?' ); + if ( cp != (char*) 0 ) /* should always find it */ + *cp = '\0'; + httpd_realloc_str( + &location, &maxlocation, + strlen( hc->encodedurl ) + 2 + strlen( hc->query ) ); + (void) my_snprintf( location, maxlocation, + "%s/?%s", hc->encodedurl, hc->query ); + } + else + { + httpd_realloc_str( + &location, &maxlocation, strlen( hc->encodedurl ) + 1 ); + (void) my_snprintf( location, maxlocation, + "%s/", hc->encodedurl ); + } + httpd_realloc_str( + &header, &maxheader, sizeof(headstr) + strlen( location ) ); + (void) my_snprintf( header, maxheader, + "%s%s\015\012", headstr, location ); + send_response( hc, 302, err302title, header, err302form, location ); + } + + +char* +httpd_method_str( int method ) + { + switch ( method ) + { + case METHOD_GET: return "GET"; + case METHOD_HEAD: return "HEAD"; + case METHOD_POST: return "POST"; + default: return "UNKNOWN"; + } + } + + +static int +hexit( char c ) + { + if ( c >= '0' && c <= '9' ) + return c - '0'; + if ( c >= 'a' && c <= 'f' ) + return c - 'a' + 10; + if ( c >= 'A' && c <= 'F' ) + return c - 'A' + 10; + return 0; /* shouldn't happen, we're guarded by isxdigit() */ + } + + +/* Copies and decodes a string. It's ok for from and to to be the +** same string. +*/ +static void +strdecode( char* to, char* from ) + { + for ( ; *from != '\0'; ++to, ++from ) + { + if ( from[0] == '%' && isxdigit( from[1] ) && isxdigit( from[2] ) ) + { + *to = hexit( from[1] ) * 16 + hexit( from[2] ); + from += 2; + } + else + *to = *from; + } + *to = '\0'; + } + + +#ifdef GENERATE_INDEXES +/* Copies and encodes a string. */ +static void +strencode( char* to, int tosize, char* from ) + { + int tolen; + + for ( tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from ) + { + if ( isalnum(*from) || strchr( "/_.-~", *from ) != (char*) 0 ) + { + *to = *from; + ++to; + ++tolen; + } + else + { + (void) sprintf( to, "%%%02x", (int) *from & 0xff ); + to += 3; + tolen += 3; + } + } + *to = '\0'; + } +#endif /* GENERATE_INDEXES */ + + +#ifdef TILDE_MAP_1 +/* Map a ~username/whatever URL into /username. */ +static int +tilde_map_1( httpd_conn* hc ) + { + static char* temp; + static size_t maxtemp = 0; + int len; + static char* prefix = TILDE_MAP_1; + + len = strlen( hc->expnfilename ) - 1; + httpd_realloc_str( &temp, &maxtemp, len ); + (void) strcpy( temp, &hc->expnfilename[1] ); + httpd_realloc_str( + &hc->expnfilename, &hc->maxexpnfilename, strlen( prefix ) + 1 + len ); + (void) strcpy( hc->expnfilename, prefix ); + if ( prefix[0] != '\0' ) + (void) strcat( hc->expnfilename, "/" ); + (void) strcat( hc->expnfilename, temp ); + return 1; + } +#endif /* TILDE_MAP_1 */ + +#ifdef TILDE_MAP_2 +/* Map a ~username/whatever URL into /. */ +static int +tilde_map_2( httpd_conn* hc ) + { + static char* temp; + static size_t maxtemp = 0; + static char* postfix = TILDE_MAP_2; + char* cp; + struct passwd* pw; + char* alt; + char* rest; + + /* Get the username. */ + httpd_realloc_str( &temp, &maxtemp, strlen( hc->expnfilename ) - 1 ); + (void) strcpy( temp, &hc->expnfilename[1] ); + cp = strchr( temp, '/' ); + if ( cp != (char*) 0 ) + *cp++ = '\0'; + else + cp = ""; + + /* Get the passwd entry. */ + pw = getpwnam( temp ); + if ( pw == (struct passwd*) 0 ) + return 0; + + /* Set up altdir. */ + httpd_realloc_str( + &hc->altdir, &hc->maxaltdir, + strlen( pw->pw_dir ) + 1 + strlen( postfix ) ); + (void) strcpy( hc->altdir, pw->pw_dir ); + if ( postfix[0] != '\0' ) + { + (void) strcat( hc->altdir, "/" ); + (void) strcat( hc->altdir, postfix ); + } + alt = expand_symlinks( hc->altdir, &rest, 0, 1 ); + if ( rest[0] != '\0' ) + return 0; + httpd_realloc_str( &hc->altdir, &hc->maxaltdir, strlen( alt ) ); + (void) strcpy( hc->altdir, alt ); + + /* And the filename becomes altdir plus the post-~ part of the original. */ + httpd_realloc_str( + &hc->expnfilename, &hc->maxexpnfilename, + strlen( hc->altdir ) + 1 + strlen( cp ) ); + (void) my_snprintf( hc->expnfilename, hc->maxexpnfilename, + "%s/%s", hc->altdir, cp ); + + /* For this type of tilde mapping, we want to defeat vhost mapping. */ + hc->tildemapped = 1; + + return 1; + } +#endif /* TILDE_MAP_2 */ + + +/* Virtual host mapping. */ +static int +vhost_map( httpd_conn* hc ) + { + httpd_sockaddr sa; + socklen_t sz; + static char* tempfilename; + static size_t maxtempfilename = 0; + char* cp1; + int len; +#ifdef VHOST_DIRLEVELS + int i; + char* cp2; +#endif /* VHOST_DIRLEVELS */ + + /* Figure out the virtual hostname. */ + if ( hc->reqhost[0] != '\0' ) + hc->hostname = hc->reqhost; + else if ( hc->hdrhost[0] != '\0' ) + hc->hostname = hc->hdrhost; + else + { + sz = sizeof(sa); + if ( getsockname( hc->conn_fd, &sa.sa, &sz ) < 0 ) + { + syslog( LOG_ERR, "getsockname - %m" ); + return 0; + } + hc->hostname = httpd_ntoa( &sa ); + } + /* Pound it to lower case. */ + for ( cp1 = hc->hostname; *cp1 != '\0'; ++cp1 ) + if ( isupper( *cp1 ) ) + *cp1 = tolower( *cp1 ); + + if ( hc->tildemapped ) + return 1; + + /* Figure out the host directory. */ +#ifdef VHOST_DIRLEVELS + httpd_realloc_str( + &hc->hostdir, &hc->maxhostdir, + strlen( hc->hostname ) + 2 * VHOST_DIRLEVELS ); + if ( strncmp( hc->hostname, "www.", 4 ) == 0 ) + cp1 = &hc->hostname[4]; + else + cp1 = hc->hostname; + for ( cp2 = hc->hostdir, i = 0; i < VHOST_DIRLEVELS; ++i ) + { + /* Skip dots in the hostname. If we don't, then we get vhost + ** directories in higher level of filestructure if dot gets + ** involved into path construction. It's `while' used here instead + ** of `if' for it's possible to have a hostname formed with two + ** dots at the end of it. + */ + while ( *cp1 == '.' ) + ++cp1; + /* Copy a character from the hostname, or '_' if we ran out. */ + if ( *cp1 != '\0' ) + *cp2++ = *cp1++; + else + *cp2++ = '_'; + /* Copy a slash. */ + *cp2++ = '/'; + } + (void) strcpy( cp2, hc->hostname ); +#else /* VHOST_DIRLEVELS */ + httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, strlen( hc->hostname ) ); + (void) strcpy( hc->hostdir, hc->hostname ); +#endif /* VHOST_DIRLEVELS */ + + /* Prepend hostdir to the filename. */ + len = strlen( hc->expnfilename ); + httpd_realloc_str( &tempfilename, &maxtempfilename, len ); + (void) strcpy( tempfilename, hc->expnfilename ); + httpd_realloc_str( + &hc->expnfilename, &hc->maxexpnfilename, + strlen( hc->hostdir ) + 1 + len ); + (void) strcpy( hc->expnfilename, hc->hostdir ); + (void) strcat( hc->expnfilename, "/" ); + (void) strcat( hc->expnfilename, tempfilename ); + return 1; + } + + +/* Expands all symlinks in the given filename, eliding ..'s and leading /'s. +** Returns the expanded path (pointer to static string), or (char*) 0 on +** errors. Also returns, in the string pointed to by restP, any trailing +** parts of the path that don't exist. +** +** This is a fairly nice little routine. It handles any size filenames +** without excessive mallocs. +*/ +static char* +expand_symlinks( char* path, char** restP, int no_symlink_check, int tildemapped ) + { + static char* checked; + static char* rest; + char lnk[5000]; + static size_t maxchecked = 0, maxrest = 0; + size_t checkedlen, restlen, linklen, prevcheckedlen, prevrestlen; + int nlinks, i; + char* r; + char* cp1; + char* cp2; + + if ( no_symlink_check ) + { + /* If we are chrooted, we can actually skip the symlink-expansion, + ** since it's impossible to get out of the tree. However, we still + ** need to do the pathinfo check, and the existing symlink expansion + ** code is a pretty reasonable way to do this. So, what we do is + ** a single stat() of the whole filename - if it exists, then we + ** return it as is with nothing in restP. If it doesn't exist, we + ** fall through to the existing code. + ** + ** One side-effect of this is that users can't symlink to central + ** approved CGIs any more. The workaround is to use the central + ** URL for the CGI instead of a local symlinked one. + */ + struct stat sb; + if ( stat( path, &sb ) != -1 ) + { + checkedlen = strlen( path ); + httpd_realloc_str( &checked, &maxchecked, checkedlen ); + (void) strcpy( checked, path ); + /* Trim trailing slashes. */ + while ( checked[checkedlen - 1] == '/' ) + { + checked[checkedlen - 1] = '\0'; + --checkedlen; + } + httpd_realloc_str( &rest, &maxrest, 0 ); + rest[0] = '\0'; + *restP = rest; + return checked; + } + } + + /* Start out with nothing in checked and the whole filename in rest. */ + httpd_realloc_str( &checked, &maxchecked, 1 ); + checked[0] = '\0'; + checkedlen = 0; + restlen = strlen( path ); + httpd_realloc_str( &rest, &maxrest, restlen ); + (void) strcpy( rest, path ); + if ( rest[restlen - 1] == '/' ) + rest[--restlen] = '\0'; /* trim trailing slash */ + if ( ! tildemapped ) + /* Remove any leading slashes. */ + while ( rest[0] == '/' ) + { + (void) ol_strcpy( rest, &(rest[1]) ); + --restlen; + } + r = rest; + nlinks = 0; + + /* While there are still components to check... */ + while ( restlen > 0 ) + { + /* Save current checkedlen in case we get a symlink. Save current + ** restlen in case we get a non-existant component. + */ + prevcheckedlen = checkedlen; + prevrestlen = restlen; + + /* Grab one component from r and transfer it to checked. */ + cp1 = strchr( r, '/' ); + if ( cp1 != (char*) 0 ) + { + i = cp1 - r; + if ( i == 0 ) + { + /* Special case for absolute paths. */ + httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 ); + (void) strncpy( &checked[checkedlen], r, 1 ); + checkedlen += 1; + } + else if ( strncmp( r, "..", MAX( i, 2 ) ) == 0 ) + { + /* Ignore ..'s that go above the start of the path. */ + if ( checkedlen != 0 ) + { + cp2 = strrchr( checked, '/' ); + if ( cp2 == (char*) 0 ) + checkedlen = 0; + else if ( cp2 == checked ) + checkedlen = 1; + else + checkedlen = cp2 - checked; + } + } + else + { + httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 + i ); + if ( checkedlen > 0 && checked[checkedlen-1] != '/' ) + checked[checkedlen++] = '/'; + (void) strncpy( &checked[checkedlen], r, i ); + checkedlen += i; + } + checked[checkedlen] = '\0'; + r += i + 1; + restlen -= i + 1; + } + else + { + /* No slashes remaining, r is all one component. */ + if ( strcmp( r, ".." ) == 0 ) + { + /* Ignore ..'s that go above the start of the path. */ + if ( checkedlen != 0 ) + { + cp2 = strrchr( checked, '/' ); + if ( cp2 == (char*) 0 ) + checkedlen = 0; + else if ( cp2 == checked ) + checkedlen = 1; + else + checkedlen = cp2 - checked; + checked[checkedlen] = '\0'; + } + } + else + { + httpd_realloc_str( + &checked, &maxchecked, checkedlen + 1 + restlen ); + if ( checkedlen > 0 && checked[checkedlen-1] != '/' ) + checked[checkedlen++] = '/'; + (void) strcpy( &checked[checkedlen], r ); + checkedlen += restlen; + } + r += restlen; + restlen = 0; + } + + /* Try reading the current filename as a symlink */ + if ( checked[0] == '\0' ) + continue; + linklen = readlink( checked, lnk, sizeof(lnk) - 1 ); + if ( linklen == -1 ) + { + if ( errno == EINVAL ) + continue; /* not a symlink */ + if ( errno == EACCES || errno == ENOENT || errno == ENOTDIR ) + { + /* That last component was bogus. Restore and return. */ + *restP = r - ( prevrestlen - restlen ); + if ( prevcheckedlen == 0 ) + (void) strcpy( checked, "." ); + else + checked[prevcheckedlen] = '\0'; + return checked; + } + syslog( LOG_ERR, "readlink %.80s - %m", checked ); + return (char*) 0; + } + ++nlinks; + if ( nlinks > MAX_LINKS ) + { + syslog( LOG_ERR, "too many symlinks in %.80s", path ); + return (char*) 0; + } + lnk[linklen] = '\0'; + if ( lnk[linklen - 1] == '/' ) + lnk[--linklen] = '\0'; /* trim trailing slash */ + + /* Insert the link contents in front of the rest of the filename. */ + if ( restlen != 0 ) + { + (void) ol_strcpy( rest, r ); + httpd_realloc_str( &rest, &maxrest, restlen + linklen + 1 ); + for ( i = restlen; i >= 0; --i ) + rest[i + linklen + 1] = rest[i]; + (void) strcpy( rest, lnk ); + rest[linklen] = '/'; + restlen += linklen + 1; + r = rest; + } + else + { + /* There's nothing left in the filename, so the link contents + ** becomes the rest. + */ + httpd_realloc_str( &rest, &maxrest, linklen ); + (void) strcpy( rest, lnk ); + restlen = linklen; + r = rest; + } + + if ( rest[0] == '/' ) + { + /* There must have been an absolute symlink - zero out checked. */ + checked[0] = '\0'; + checkedlen = 0; + } + else + { + /* Re-check this component. */ + checkedlen = prevcheckedlen; + checked[checkedlen] = '\0'; + } + } + + /* Ok. */ + *restP = r; + if ( checked[0] == '\0' ) + (void) strcpy( checked, "." ); + return checked; + } + + +int +httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc ) + { + httpd_sockaddr sa; + socklen_t sz; + + if ( ! hc->initialized ) + { + hc->read_size = 0; + httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 ); + hc->maxdecodedurl = + hc->maxorigfilename = hc->maxexpnfilename = hc->maxencodings = + hc->maxpathinfo = hc->maxquery = hc->maxaccept = + hc->maxaccepte = hc->maxreqhost = hc->maxhostdir = + hc->maxremoteuser = hc->maxresponse = 0; +#ifdef TILDE_MAP_2 + hc->maxaltdir = 0; +#endif /* TILDE_MAP_2 */ + httpd_realloc_str( &hc->decodedurl, &hc->maxdecodedurl, 1 ); + httpd_realloc_str( &hc->origfilename, &hc->maxorigfilename, 1 ); + httpd_realloc_str( &hc->expnfilename, &hc->maxexpnfilename, 0 ); + httpd_realloc_str( &hc->encodings, &hc->maxencodings, 0 ); + httpd_realloc_str( &hc->pathinfo, &hc->maxpathinfo, 0 ); + httpd_realloc_str( &hc->query, &hc->maxquery, 0 ); + httpd_realloc_str( &hc->accept, &hc->maxaccept, 0 ); + httpd_realloc_str( &hc->accepte, &hc->maxaccepte, 0 ); + httpd_realloc_str( &hc->reqhost, &hc->maxreqhost, 0 ); + httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, 0 ); + httpd_realloc_str( &hc->remoteuser, &hc->maxremoteuser, 0 ); + httpd_realloc_str( &hc->response, &hc->maxresponse, 0 ); +#ifdef TILDE_MAP_2 + httpd_realloc_str( &hc->altdir, &hc->maxaltdir, 0 ); +#endif /* TILDE_MAP_2 */ + hc->initialized = 1; + } + + /* Accept the new connection. */ + sz = sizeof(sa); + hc->conn_fd = accept( listen_fd, &sa.sa, &sz ); + if ( hc->conn_fd < 0 ) + { + if ( errno == EWOULDBLOCK ) + return GC_NO_MORE; + /* ECONNABORTED means the connection was closed by the client while + ** it was waiting in the listen queue. It's not worth logging. + */ + if ( errno != ECONNABORTED ) + syslog( LOG_ERR, "accept - %m" ); + return GC_FAIL; + } + if ( ! sockaddr_check( &sa ) ) + { + syslog( LOG_ERR, "unknown sockaddr family" ); + close( hc->conn_fd ); + hc->conn_fd = -1; + return GC_FAIL; + } + (void) fcntl( hc->conn_fd, F_SETFD, 1 ); + hc->hs = hs; + (void) memset( &hc->client_addr, 0, sizeof(hc->client_addr) ); + (void) memmove( &hc->client_addr, &sa, sockaddr_len( &sa ) ); + hc->read_idx = 0; + hc->checked_idx = 0; + hc->checked_state = CHST_FIRSTWORD; + hc->method = METHOD_UNKNOWN; + hc->status = 0; + hc->bytes_to_send = 0; + hc->bytes_sent = 0; + hc->encodedurl = ""; + hc->decodedurl[0] = '\0'; + hc->protocol = "UNKNOWN"; + hc->origfilename[0] = '\0'; + hc->expnfilename[0] = '\0'; + hc->encodings[0] = '\0'; + hc->pathinfo[0] = '\0'; + hc->query[0] = '\0'; + hc->referrer = ""; + hc->useragent = ""; + hc->accept[0] = '\0'; + hc->accepte[0] = '\0'; + hc->acceptl = ""; + hc->cookie = ""; + hc->contenttype = ""; + hc->reqhost[0] = '\0'; + hc->hdrhost = ""; + hc->hostdir[0] = '\0'; + hc->authorization = ""; + hc->remoteuser[0] = '\0'; + hc->response[0] = '\0'; +#ifdef TILDE_MAP_2 + hc->altdir[0] = '\0'; +#endif /* TILDE_MAP_2 */ + hc->responselen = 0; + hc->if_modified_since = (time_t) -1; + hc->range_if = (time_t) -1; + hc->contentlength = -1; + hc->type = ""; + hc->hostname = (char*) 0; + hc->mime_flag = 1; + hc->one_one = 0; + hc->got_range = 0; + hc->tildemapped = 0; + hc->first_byte_index = 0; + hc->last_byte_index = -1; + hc->keep_alive = 0; + hc->should_linger = 0; + hc->file_address = (char*) 0; + return GC_OK; + } + + +/* Checks hc->read_buf to see whether a complete request has been read so far; +** either the first line has two words (an HTTP/0.9 request), or the first +** line has three words and there's a blank line present. +** +** hc->read_idx is how much has been read in; hc->checked_idx is how much we +** have checked so far; and hc->checked_state is the current state of the +** finite state machine. +*/ +int +httpd_got_request( httpd_conn* hc ) + { + char c; + + for ( ; hc->checked_idx < hc->read_idx; ++hc->checked_idx ) + { + c = hc->read_buf[hc->checked_idx]; + switch ( hc->checked_state ) + { + case CHST_FIRSTWORD: + switch ( c ) + { + case ' ': case '\t': + hc->checked_state = CHST_FIRSTWS; + break; + case '\012': case '\015': + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + } + break; + case CHST_FIRSTWS: + switch ( c ) + { + case ' ': case '\t': + break; + case '\012': case '\015': + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + default: + hc->checked_state = CHST_SECONDWORD; + break; + } + break; + case CHST_SECONDWORD: + switch ( c ) + { + case ' ': case '\t': + hc->checked_state = CHST_SECONDWS; + break; + case '\012': case '\015': + /* The first line has only two words - an HTTP/0.9 request. */ + return GR_GOT_REQUEST; + } + break; + case CHST_SECONDWS: + switch ( c ) + { + case ' ': case '\t': + break; + case '\012': case '\015': + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + default: + hc->checked_state = CHST_THIRDWORD; + break; + } + break; + case CHST_THIRDWORD: + switch ( c ) + { + case ' ': case '\t': + hc->checked_state = CHST_THIRDWS; + break; + case '\012': + hc->checked_state = CHST_LF; + break; + case '\015': + hc->checked_state = CHST_CR; + break; + } + break; + case CHST_THIRDWS: + switch ( c ) + { + case ' ': case '\t': + break; + case '\012': + hc->checked_state = CHST_LF; + break; + case '\015': + hc->checked_state = CHST_CR; + break; + default: + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + } + break; + case CHST_LINE: + switch ( c ) + { + case '\012': + hc->checked_state = CHST_LF; + break; + case '\015': + hc->checked_state = CHST_CR; + break; + } + break; + case CHST_LF: + switch ( c ) + { + case '\012': + /* Two newlines in a row - a blank line - end of request. */ + return GR_GOT_REQUEST; + case '\015': + hc->checked_state = CHST_CR; + break; + default: + hc->checked_state = CHST_LINE; + break; + } + break; + case CHST_CR: + switch ( c ) + { + case '\012': + hc->checked_state = CHST_CRLF; + break; + case '\015': + /* Two returns in a row - end of request. */ + return GR_GOT_REQUEST; + default: + hc->checked_state = CHST_LINE; + break; + } + break; + case CHST_CRLF: + switch ( c ) + { + case '\012': + /* Two newlines in a row - end of request. */ + return GR_GOT_REQUEST; + case '\015': + hc->checked_state = CHST_CRLFCR; + break; + default: + hc->checked_state = CHST_LINE; + break; + } + break; + case CHST_CRLFCR: + switch ( c ) + { + case '\012': case '\015': + /* Two CRLFs or two CRs in a row - end of request. */ + return GR_GOT_REQUEST; + default: + hc->checked_state = CHST_LINE; + break; + } + break; + case CHST_BOGUS: + return GR_BAD_REQUEST; + } + } + return GR_NO_REQUEST; + } + + +int +httpd_parse_request( httpd_conn* hc ) + { + char* buf; + char* method_str; + char* url; + char* protocol; + char* reqhost; + char* eol; + char* cp; + char* pi; + + hc->checked_idx = 0; /* reset */ + method_str = bufgets( hc ); + url = strpbrk( method_str, " \t\012\015" ); + if ( url == (char*) 0 ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + *url++ = '\0'; + url += strspn( url, " \t\012\015" ); + protocol = strpbrk( url, " \t\012\015" ); + if ( protocol == (char*) 0 ) + { + protocol = "HTTP/0.9"; + hc->mime_flag = 0; + } + else + { + *protocol++ = '\0'; + protocol += strspn( protocol, " \t\012\015" ); + if ( *protocol != '\0' ) + { + eol = strpbrk( protocol, " \t\012\015" ); + if ( eol != (char*) 0 ) + *eol = '\0'; + if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 ) + hc->one_one = 1; + } + } + hc->protocol = protocol; + + /* Check for HTTP/1.1 absolute URL. */ + if ( strncasecmp( url, "http://", 7 ) == 0 ) + { + if ( ! hc->one_one ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + reqhost = url + 7; + url = strchr( reqhost, '/' ); + if ( url == (char*) 0 ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + *url = '\0'; + if ( strchr( reqhost, '/' ) != (char*) 0 || reqhost[0] == '.' ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + httpd_realloc_str( &hc->reqhost, &hc->maxreqhost, strlen( reqhost ) ); + (void) strcpy( hc->reqhost, reqhost ); + *url = '/'; + } + + if ( *url != '/' ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + + if ( strcasecmp( method_str, httpd_method_str( METHOD_GET ) ) == 0 ) + hc->method = METHOD_GET; + else if ( strcasecmp( method_str, httpd_method_str( METHOD_HEAD ) ) == 0 ) + hc->method = METHOD_HEAD; + else if ( strcasecmp( method_str, httpd_method_str( METHOD_POST ) ) == 0 ) + hc->method = METHOD_POST; + else + { + httpd_send_err( hc, 501, err501title, "", err501form, method_str ); + return -1; + } + + hc->encodedurl = url; + httpd_realloc_str( + &hc->decodedurl, &hc->maxdecodedurl, strlen( hc->encodedurl ) ); + strdecode( hc->decodedurl, hc->encodedurl ); + + httpd_realloc_str( + &hc->origfilename, &hc->maxorigfilename, strlen( hc->decodedurl ) ); + (void) strcpy( hc->origfilename, &hc->decodedurl[1] ); + /* Special case for top-level URL. */ + if ( hc->origfilename[0] == '\0' ) + (void) strcpy( hc->origfilename, "." ); + + /* Extract query string from encoded URL. */ + cp = strchr( hc->encodedurl, '?' ); + if ( cp != (char*) 0 ) + { + ++cp; + httpd_realloc_str( &hc->query, &hc->maxquery, strlen( cp ) ); + (void) strcpy( hc->query, cp ); + /* Remove query from (decoded) origfilename. */ + cp = strchr( hc->origfilename, '?' ); + if ( cp != (char*) 0 ) + *cp = '\0'; + } + + de_dotdot( hc->origfilename ); + if ( hc->origfilename[0] == '/' || + ( hc->origfilename[0] == '.' && hc->origfilename[1] == '.' && + ( hc->origfilename[2] == '\0' || hc->origfilename[2] == '/' ) ) ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + + if ( hc->mime_flag ) + { + /* Read the MIME headers. */ + while ( ( buf = bufgets( hc ) ) != (char*) 0 ) + { + if ( buf[0] == '\0' ) + break; + if ( strncasecmp( buf, "Referer:", 8 ) == 0 ) + { + cp = &buf[8]; + cp += strspn( cp, " \t" ); + hc->referrer = cp; + } + else if ( strncasecmp( buf, "Referrer:", 9 ) == 0 ) + { + cp = &buf[9]; + cp += strspn( cp, " \t" ); + hc->referrer = cp; + } + else if ( strncasecmp( buf, "User-Agent:", 11 ) == 0 ) + { + cp = &buf[11]; + cp += strspn( cp, " \t" ); + hc->useragent = cp; + } + else if ( strncasecmp( buf, "Host:", 5 ) == 0 ) + { + cp = &buf[5]; + cp += strspn( cp, " \t" ); + hc->hdrhost = cp; + cp = strchr( hc->hdrhost, ':' ); + if ( cp != (char*) 0 ) + *cp = '\0'; + if ( strchr( hc->hdrhost, '/' ) != (char*) 0 || hc->hdrhost[0] == '.' ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + } + else if ( strncasecmp( buf, "Accept:", 7 ) == 0 ) + { + cp = &buf[7]; + cp += strspn( cp, " \t" ); + if ( hc->accept[0] != '\0' ) + { + if ( strlen( hc->accept ) > 5000 ) + { + syslog( + LOG_ERR, "%.80s way too much Accept: data", + httpd_ntoa( &hc->client_addr ) ); + continue; + } + httpd_realloc_str( + &hc->accept, &hc->maxaccept, + strlen( hc->accept ) + 2 + strlen( cp ) ); + (void) strcat( hc->accept, ", " ); + } + else + httpd_realloc_str( + &hc->accept, &hc->maxaccept, strlen( cp ) ); + (void) strcat( hc->accept, cp ); + } + else if ( strncasecmp( buf, "Accept-Encoding:", 16 ) == 0 ) + { + cp = &buf[16]; + cp += strspn( cp, " \t" ); + if ( hc->accepte[0] != '\0' ) + { + if ( strlen( hc->accepte ) > 5000 ) + { + syslog( + LOG_ERR, "%.80s way too much Accept-Encoding: data", + httpd_ntoa( &hc->client_addr ) ); + continue; + } + httpd_realloc_str( + &hc->accepte, &hc->maxaccepte, + strlen( hc->accepte ) + 2 + strlen( cp ) ); + (void) strcat( hc->accepte, ", " ); + } + else + httpd_realloc_str( + &hc->accepte, &hc->maxaccepte, strlen( cp ) ); + (void) strcpy( hc->accepte, cp ); + } + else if ( strncasecmp( buf, "Accept-Language:", 16 ) == 0 ) + { + cp = &buf[16]; + cp += strspn( cp, " \t" ); + hc->acceptl = cp; + } + else if ( strncasecmp( buf, "If-Modified-Since:", 18 ) == 0 ) + { + cp = &buf[18]; + hc->if_modified_since = tdate_parse( cp ); + if ( hc->if_modified_since == (time_t) -1 ) + syslog( LOG_DEBUG, "unparsable time: %.80s", cp ); + } + else if ( strncasecmp( buf, "Cookie:", 7 ) == 0 ) + { + cp = &buf[7]; + cp += strspn( cp, " \t" ); + hc->cookie = cp; + } + else if ( strncasecmp( buf, "Range:", 6 ) == 0 ) + { + /* Only support %d- and %d-%d, not %d-%d,%d-%d or -%d. */ + if ( strchr( buf, ',' ) == (char*) 0 ) + { + char* cp_dash; + cp = strpbrk( buf, "=" ); + if ( cp != (char*) 0 ) + { + cp_dash = strchr( cp + 1, '-' ); + if ( cp_dash != (char*) 0 && cp_dash != cp + 1 ) + { + *cp_dash = '\0'; + hc->got_range = 1; + hc->first_byte_index = atoll( cp + 1 ); + if ( hc->first_byte_index < 0 ) + hc->first_byte_index = 0; + if ( isdigit( (int) cp_dash[1] ) ) + { + hc->last_byte_index = atoll( cp_dash + 1 ); + if ( hc->last_byte_index < 0 ) + hc->last_byte_index = -1; + } + } + } + } + } + else if ( strncasecmp( buf, "Range-If:", 9 ) == 0 || + strncasecmp( buf, "If-Range:", 9 ) == 0 ) + { + cp = &buf[9]; + hc->range_if = tdate_parse( cp ); + if ( hc->range_if == (time_t) -1 ) + syslog( LOG_DEBUG, "unparsable time: %.80s", cp ); + } + else if ( strncasecmp( buf, "Content-Type:", 13 ) == 0 ) + { + cp = &buf[13]; + cp += strspn( cp, " \t" ); + hc->contenttype = cp; + } + else if ( strncasecmp( buf, "Content-Length:", 15 ) == 0 ) + { + cp = &buf[15]; + hc->contentlength = atol( cp ); + } + else if ( strncasecmp( buf, "Authorization:", 14 ) == 0 ) + { + cp = &buf[14]; + cp += strspn( cp, " \t" ); + hc->authorization = cp; + } + else if ( strncasecmp( buf, "Connection:", 11 ) == 0 ) + { + cp = &buf[11]; + cp += strspn( cp, " \t" ); + if ( strcasecmp( cp, "keep-alive" ) == 0 ) + hc->keep_alive = 1; + } +#ifdef LOG_UNKNOWN_HEADERS + else if ( strncasecmp( buf, "Accept-Charset:", 15 ) == 0 || + strncasecmp( buf, "Accept-Language:", 16 ) == 0 || + strncasecmp( buf, "Agent:", 6 ) == 0 || + strncasecmp( buf, "Cache-Control:", 14 ) == 0 || + strncasecmp( buf, "Cache-Info:", 11 ) == 0 || + strncasecmp( buf, "Charge-To:", 10 ) == 0 || + strncasecmp( buf, "Client-IP:", 10 ) == 0 || + strncasecmp( buf, "Date:", 5 ) == 0 || + strncasecmp( buf, "Extension:", 10 ) == 0 || + strncasecmp( buf, "Forwarded:", 10 ) == 0 || + strncasecmp( buf, "From:", 5 ) == 0 || + strncasecmp( buf, "HTTP-Version:", 13 ) == 0 || + strncasecmp( buf, "Max-Forwards:", 13 ) == 0 || + strncasecmp( buf, "Message-Id:", 11 ) == 0 || + strncasecmp( buf, "MIME-Version:", 13 ) == 0 || + strncasecmp( buf, "Negotiate:", 10 ) == 0 || + strncasecmp( buf, "Pragma:", 7 ) == 0 || + strncasecmp( buf, "Proxy-Agent:", 12 ) == 0 || + strncasecmp( buf, "Proxy-Connection:", 17 ) == 0 || + strncasecmp( buf, "Security-Scheme:", 16 ) == 0 || + strncasecmp( buf, "Session-Id:", 11 ) == 0 || + strncasecmp( buf, "UA-Color:", 9 ) == 0 || + strncasecmp( buf, "UA-CPU:", 7 ) == 0 || + strncasecmp( buf, "UA-Disp:", 8 ) == 0 || + strncasecmp( buf, "UA-OS:", 6 ) == 0 || + strncasecmp( buf, "UA-Pixels:", 10 ) == 0 || + strncasecmp( buf, "User:", 5 ) == 0 || + strncasecmp( buf, "Via:", 4 ) == 0 || + strncasecmp( buf, "X-", 2 ) == 0 ) + ; /* ignore */ + else + syslog( LOG_DEBUG, "unknown request header: %.80s", buf ); +#endif /* LOG_UNKNOWN_HEADERS */ + } + } + + if ( hc->one_one ) + { + /* Check that HTTP/1.1 requests specify a host, as required. */ + if ( hc->reqhost[0] == '\0' && hc->hdrhost[0] == '\0' ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + return -1; + } + + /* If the client wants to do keep-alives, it might also be doing + ** pipelining. There's no way for us to tell. Since we don't + ** implement keep-alives yet, if we close such a connection there + ** might be unread pipelined requests waiting. So, we have to + ** do a lingering close. + */ + if ( hc->keep_alive ) + hc->should_linger = 1; + } + + /* Ok, the request has been parsed. Now we resolve stuff that + ** may require the entire request. + */ + + /* Copy original filename to expanded filename. */ + httpd_realloc_str( + &hc->expnfilename, &hc->maxexpnfilename, strlen( hc->origfilename ) ); + (void) strcpy( hc->expnfilename, hc->origfilename ); + + /* Tilde mapping. */ + if ( hc->expnfilename[0] == '~' ) + { +#ifdef TILDE_MAP_1 + if ( ! tilde_map_1( hc ) ) + { + httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl ); + return -1; + } +#endif /* TILDE_MAP_1 */ +#ifdef TILDE_MAP_2 + if ( ! tilde_map_2( hc ) ) + { + httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl ); + return -1; + } +#endif /* TILDE_MAP_2 */ + } + + /* Virtual host mapping. */ + if ( hc->hs->vhost ) + if ( ! vhost_map( hc ) ) + { + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + + /* Expand all symbolic links in the filename. This also gives us + ** any trailing non-existing components, for pathinfo. + */ + cp = expand_symlinks( hc->expnfilename, &pi, hc->hs->no_symlink_check, hc->tildemapped ); + if ( cp == (char*) 0 ) + { + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + httpd_realloc_str( &hc->expnfilename, &hc->maxexpnfilename, strlen( cp ) ); + (void) strcpy( hc->expnfilename, cp ); + httpd_realloc_str( &hc->pathinfo, &hc->maxpathinfo, strlen( pi ) ); + (void) strcpy( hc->pathinfo, pi ); + + /* Remove pathinfo stuff from the original filename too. */ + if ( hc->pathinfo[0] != '\0' ) + { + int i; + i = strlen( hc->origfilename ) - strlen( hc->pathinfo ); + if ( i > 0 && strcmp( &hc->origfilename[i], hc->pathinfo ) == 0 ) + hc->origfilename[i - 1] = '\0'; + } + + /* If the expanded filename is an absolute path, check that it's still + ** within the current directory or the alternate directory. + */ + if ( hc->expnfilename[0] == '/' ) + { + if ( strncmp( + hc->expnfilename, hc->hs->cwd, strlen( hc->hs->cwd ) ) == 0 ) + { + /* Elide the current directory. */ + (void) ol_strcpy( + hc->expnfilename, &hc->expnfilename[strlen( hc->hs->cwd )] ); + } +#ifdef TILDE_MAP_2 + else if ( hc->altdir[0] != '\0' && + ( strncmp( + hc->expnfilename, hc->altdir, + strlen( hc->altdir ) ) == 0 && + ( hc->expnfilename[strlen( hc->altdir )] == '\0' || + hc->expnfilename[strlen( hc->altdir )] == '/' ) ) ) + {} +#endif /* TILDE_MAP_2 */ + else + { + syslog( + LOG_NOTICE, "%.80s URL \"%.80s\" goes outside the web tree", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file outside the permitted web server directory tree.\n" ), + hc->encodedurl ); + return -1; + } + } + + return 0; + } + + +static char* +bufgets( httpd_conn* hc ) + { + int i; + char c; + + for ( i = hc->checked_idx; hc->checked_idx < hc->read_idx; ++hc->checked_idx ) + { + c = hc->read_buf[hc->checked_idx]; + if ( c == '\012' || c == '\015' ) + { + hc->read_buf[hc->checked_idx] = '\0'; + ++hc->checked_idx; + if ( c == '\015' && hc->checked_idx < hc->read_idx && + hc->read_buf[hc->checked_idx] == '\012' ) + { + hc->read_buf[hc->checked_idx] = '\0'; + ++hc->checked_idx; + } + return &(hc->read_buf[i]); + } + } + return (char*) 0; + } + + +static void +de_dotdot( char* file ) + { + char* cp; + char* cp2; + int l; + + /* Collapse any multiple / sequences. */ + while ( ( cp = strstr( file, "//") ) != (char*) 0 ) + { + for ( cp2 = cp + 2; *cp2 == '/'; ++cp2 ) + continue; + (void) ol_strcpy( cp + 1, cp2 ); + } + + /* Remove leading ./ and any /./ sequences. */ + while ( strncmp( file, "./", 2 ) == 0 ) + (void) ol_strcpy( file, file + 2 ); + while ( ( cp = strstr( file, "/./") ) != (char*) 0 ) + (void) ol_strcpy( cp, cp + 2 ); + + /* Alternate between removing leading ../ and removing xxx/../ */ + for (;;) + { + while ( strncmp( file, "../", 3 ) == 0 ) + (void) ol_strcpy( file, file + 3 ); + cp = strstr( file, "/../" ); + if ( cp == (char*) 0 ) + break; + for ( cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2 ) + continue; + (void) ol_strcpy( cp2 + 1, cp + 4 ); + } + + /* Also elide any xxx/.. at the end. */ + while ( ( l = strlen( file ) ) > 3 && + strcmp( ( cp = file + l - 3 ), "/.." ) == 0 ) + { + for ( cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2 ) + continue; + if ( cp2 < file ) + break; + *cp2 = '\0'; + } + } + + +void +httpd_close_conn( httpd_conn* hc, struct timeval* nowP ) + { + make_log_entry( hc, nowP ); + + if ( hc->file_address != (char*) 0 ) + { + mmc_unmap( hc->file_address, &(hc->sb), nowP ); + hc->file_address = (char*) 0; + } + if ( hc->conn_fd >= 0 ) + { + (void) close( hc->conn_fd ); + hc->conn_fd = -1; + } + } + +void +httpd_destroy_conn( httpd_conn* hc ) + { + if ( hc->initialized ) + { + free( (void*) hc->read_buf ); + free( (void*) hc->decodedurl ); + free( (void*) hc->origfilename ); + free( (void*) hc->expnfilename ); + free( (void*) hc->encodings ); + free( (void*) hc->pathinfo ); + free( (void*) hc->query ); + free( (void*) hc->accept ); + free( (void*) hc->accepte ); + free( (void*) hc->reqhost ); + free( (void*) hc->hostdir ); + free( (void*) hc->remoteuser ); + free( (void*) hc->response ); +#ifdef TILDE_MAP_2 + free( (void*) hc->altdir ); +#endif /* TILDE_MAP_2 */ + hc->initialized = 0; + } + } + + +struct mime_entry { + char* ext; + size_t ext_len; + char* val; + size_t val_len; + }; +static struct mime_entry enc_tab[] = { +#include "mime_encodings.h" + }; +static const int n_enc_tab = sizeof(enc_tab) / sizeof(*enc_tab); +static struct mime_entry typ_tab[] = { +#include "mime_types.h" + }; +static const int n_typ_tab = sizeof(typ_tab) / sizeof(*typ_tab); + + +/* qsort comparison routine */ +static int +ext_compare( const void* v1, const void* v2 ) + { + const struct mime_entry* m1 = (const struct mime_entry*) v1; + const struct mime_entry* m2 = (const struct mime_entry*) v2; + + return strcmp( m1->ext, m2->ext ); + } + + +static void +init_mime( void ) + { + int i; + + /* Sort the tables so we can do binary search. */ + qsort( enc_tab, n_enc_tab, sizeof(*enc_tab), ext_compare ); + qsort( typ_tab, n_typ_tab, sizeof(*typ_tab), ext_compare ); + + /* Fill in the lengths. */ + for ( i = 0; i < n_enc_tab; ++i ) + { + enc_tab[i].ext_len = strlen( enc_tab[i].ext ); + enc_tab[i].val_len = strlen( enc_tab[i].val ); + } + for ( i = 0; i < n_typ_tab; ++i ) + { + typ_tab[i].ext_len = strlen( typ_tab[i].ext ); + typ_tab[i].val_len = strlen( typ_tab[i].val ); + } + + } + + +/* Figure out MIME encodings and type based on the filename. Multiple +** encodings are separated by commas, and are listed in the order in +** which they were applied to the file. +*/ +static void +figure_mime( httpd_conn* hc ) + { + char* prev_dot; + char* dot; + char* ext; + int me_indexes[100], n_me_indexes; + size_t ext_len, encodings_len; + int i, top, bot, mid; + int r; + char* default_type = "text/plain; charset=%s"; + + /* Peel off encoding extensions until there aren't any more. */ + n_me_indexes = 0; + for ( prev_dot = &hc->expnfilename[strlen(hc->expnfilename)]; ; prev_dot = dot ) + { + for ( dot = prev_dot - 1; dot >= hc->expnfilename && *dot != '.'; --dot ) + ; + if ( dot < hc->expnfilename ) + { + /* No dot found. No more encoding extensions, and no type + ** extension either. + */ + hc->type = default_type; + goto done; + } + ext = dot + 1; + ext_len = prev_dot - ext; + /* Search the encodings table. Linear search is fine here, there + ** are only a few entries. + */ + for ( i = 0; i < n_enc_tab; ++i ) + { + if ( ext_len == enc_tab[i].ext_len && strncasecmp( ext, enc_tab[i].ext, ext_len ) == 0 ) + { + if ( n_me_indexes < sizeof(me_indexes)/sizeof(*me_indexes) ) + { + me_indexes[n_me_indexes] = i; + ++n_me_indexes; + } + goto next; + } + } + /* No encoding extension found. Break and look for a type extension. */ + break; + + next: ; + } + + /* Binary search for a matching type extension. */ + top = n_typ_tab - 1; + bot = 0; + while ( top >= bot ) + { + mid = ( top + bot ) / 2; + r = strncasecmp( ext, typ_tab[mid].ext, ext_len ); + if ( r < 0 ) + top = mid - 1; + else if ( r > 0 ) + bot = mid + 1; + else + if ( ext_len < typ_tab[mid].ext_len ) + top = mid - 1; + else if ( ext_len > typ_tab[mid].ext_len ) + bot = mid + 1; + else + { + hc->type = typ_tab[mid].val; + goto done; + } + } + hc->type = default_type; + + done: + + /* The last thing we do is actually generate the mime-encoding header. */ + hc->encodings[0] = '\0'; + encodings_len = 0; + for ( i = n_me_indexes - 1; i >= 0; --i ) + { + httpd_realloc_str( + &hc->encodings, &hc->maxencodings, + encodings_len + enc_tab[me_indexes[i]].val_len + 1 ); + if ( hc->encodings[0] != '\0' ) + { + (void) strcpy( &hc->encodings[encodings_len], "," ); + ++encodings_len; + } + (void) strcpy( &hc->encodings[encodings_len], enc_tab[me_indexes[i]].val ); + encodings_len += enc_tab[me_indexes[i]].val_len; + } + + } + + +#ifdef CGI_TIMELIMIT +static void +cgi_kill2( ClientData client_data, struct timeval* nowP ) + { + pid_t pid; + + pid = (pid_t) client_data.i; + if ( kill( pid, SIGKILL ) == 0 ) + syslog( LOG_WARNING, "hard-killed CGI process %d", pid ); + } + +static void +cgi_kill( ClientData client_data, struct timeval* nowP ) + { + pid_t pid; + + pid = (pid_t) client_data.i; + if ( kill( pid, SIGINT ) == 0 ) + { + syslog( LOG_WARNING, "killed CGI process %d", pid ); + /* In case this isn't enough, schedule an uncatchable kill. */ + if ( tmr_create( nowP, cgi_kill2, client_data, 5 * 1000L, 0 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(cgi_kill2) failed" ); + exit( 1 ); + } + } + } +#endif /* CGI_TIMELIMIT */ + + +#ifdef GENERATE_INDEXES + +/* qsort comparison routine */ +static int +name_compare( const void* v1, const void* v2 ) + { + const char** c1 = (const char**) v1; + const char** c2 = (const char**) v2; + return strcmp( *c1, *c2 ); + } + + +static int +ls( httpd_conn* hc ) + { + DIR* dirp; + struct dirent* de; + int namlen; + static int maxnames = 0; + int nnames; + static char* names; + static char** nameptrs; + static char* name; + static size_t maxname = 0; + static char* rname; + static size_t maxrname = 0; + static char* encrname; + static size_t maxencrname = 0; + FILE* fp; + int i, r; + struct stat sb; + struct stat lsb; + char modestr[20]; + char* linkprefix; + char lnk[MAXPATHLEN+1]; + int linklen; + char* fileclass; + time_t now; + char* timestr; + ClientData client_data; + + dirp = opendir( hc->expnfilename ); + if ( dirp == (DIR*) 0 ) + { + syslog( LOG_ERR, "opendir %.80s - %m", hc->expnfilename ); + httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl ); + return -1; + } + + if ( hc->method == METHOD_HEAD ) + { + closedir( dirp ); + send_mime( + hc, 200, ok200title, "", "", "text/html; charset=%s", (off_t) -1, + hc->sb.st_mtime ); + } + else if ( hc->method == METHOD_GET ) + { + if ( hc->hs->cgi_limit != 0 && hc->hs->cgi_count >= hc->hs->cgi_limit ) + { + closedir( dirp ); + httpd_send_err( + hc, 503, httpd_err503title, "", httpd_err503form, + hc->encodedurl ); + return -1; + } + ++hc->hs->cgi_count; + r = fork( ); + if ( r < 0 ) + { + syslog( LOG_ERR, "fork - %m" ); + closedir( dirp ); + httpd_send_err( + hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + if ( r == 0 ) + { + /* Child process. */ + sub_process = 1; + httpd_unlisten( hc->hs ); + send_mime( + hc, 200, ok200title, "", "", "text/html; charset=%s", + (off_t) -1, hc->sb.st_mtime ); + httpd_write_response( hc ); + +#ifdef CGI_NICE + /* Set priority. */ + (void) nice( CGI_NICE ); +#endif /* CGI_NICE */ + + /* Open a stdio stream so that we can use fprintf, which is more + ** efficient than a bunch of separate write()s. We don't have + ** to worry about double closes or file descriptor leaks cause + ** we're in a subprocess. + */ + fp = fdopen( hc->conn_fd, "w" ); + if ( fp == (FILE*) 0 ) + { + syslog( LOG_ERR, "fdopen - %m" ); + httpd_send_err( + hc, 500, err500title, "", err500form, hc->encodedurl ); + httpd_write_response( hc ); + closedir( dirp ); + exit( 1 ); + } + + (void) fprintf( fp, "\ +\n\ +\n\ +\n\ +\n\ + \n\ + \n\ + Index of %.80s\n\ + \n\ +\n\ + \n\ +\n\ +

Index of %.80s

\n\ +\n\ +
\n\
+mode  links    bytes  last-changed  name\n\
+    
", + hc->encodedurl, hc->encodedurl ); + + /* Read in names. */ + nnames = 0; + while ( ( de = readdir( dirp ) ) != 0 ) /* dirent or direct */ + { + if ( nnames >= maxnames ) + { + if ( maxnames == 0 ) + { + maxnames = 100; + names = NEW( char, maxnames * ( MAXPATHLEN + 1 ) ); + nameptrs = NEW( char*, maxnames ); + } + else + { + maxnames *= 2; + names = RENEW( names, char, maxnames * ( MAXPATHLEN + 1 ) ); + nameptrs = RENEW( nameptrs, char*, maxnames ); + } + if ( names == (char*) 0 || nameptrs == (char**) 0 ) + { + syslog( LOG_ERR, "out of memory reallocating directory names" ); + exit( 1 ); + } + for ( i = 0; i < maxnames; ++i ) + nameptrs[i] = &names[i * ( MAXPATHLEN + 1 )]; + } + namlen = NAMLEN(de); + (void) strncpy( nameptrs[nnames], de->d_name, namlen ); + nameptrs[nnames][namlen] = '\0'; + ++nnames; + } + closedir( dirp ); + + /* Sort the names. */ + qsort( nameptrs, nnames, sizeof(*nameptrs), name_compare ); + + /* Generate output. */ + for ( i = 0; i < nnames; ++i ) + { + httpd_realloc_str( + &name, &maxname, + strlen( hc->expnfilename ) + 1 + strlen( nameptrs[i] ) ); + httpd_realloc_str( + &rname, &maxrname, + strlen( hc->origfilename ) + 1 + strlen( nameptrs[i] ) ); + if ( hc->expnfilename[0] == '\0' || + strcmp( hc->expnfilename, "." ) == 0 ) + { + (void) strcpy( name, nameptrs[i] ); + (void) strcpy( rname, nameptrs[i] ); + } + else + { + (void) my_snprintf( name, maxname, + "%s/%s", hc->expnfilename, nameptrs[i] ); + if ( strcmp( hc->origfilename, "." ) == 0 ) + (void) my_snprintf( rname, maxrname, + "%s", nameptrs[i] ); + else + (void) my_snprintf( rname, maxrname, + "%s%s", hc->origfilename, nameptrs[i] ); + } + httpd_realloc_str( + &encrname, &maxencrname, 3 * strlen( rname ) + 1 ); + strencode( encrname, maxencrname, rname ); + + if ( stat( name, &sb ) < 0 || lstat( name, &lsb ) < 0 ) + continue; + + linkprefix = ""; + lnk[0] = '\0'; + /* Break down mode word. First the file type. */ + switch ( lsb.st_mode & S_IFMT ) + { + case S_IFIFO: modestr[0] = 'p'; break; + case S_IFCHR: modestr[0] = 'c'; break; + case S_IFDIR: modestr[0] = 'd'; break; + case S_IFBLK: modestr[0] = 'b'; break; + case S_IFREG: modestr[0] = '-'; break; + case S_IFSOCK: modestr[0] = 's'; break; + case S_IFLNK: modestr[0] = 'l'; + linklen = readlink( name, lnk, sizeof(lnk) - 1 ); + if ( linklen != -1 ) + { + lnk[linklen] = '\0'; + linkprefix = " -> "; + } + break; + default: modestr[0] = '?'; break; + } + /* Now the world permissions. Owner and group permissions + ** are not of interest to web clients. + */ + modestr[1] = ( lsb.st_mode & S_IROTH ) ? 'r' : '-'; + modestr[2] = ( lsb.st_mode & S_IWOTH ) ? 'w' : '-'; + modestr[3] = ( lsb.st_mode & S_IXOTH ) ? 'x' : '-'; + modestr[4] = '\0'; + + /* We also leave out the owner and group name, they are + ** also not of interest to web clients. Plus if we're + ** running under chroot(), they would require a copy + ** of /etc/passwd and /etc/group, which we want to avoid. + */ + + /* Get time string. */ + now = time( (time_t*) 0 ); + timestr = ctime( &lsb.st_mtime ); + timestr[ 0] = timestr[ 4]; + timestr[ 1] = timestr[ 5]; + timestr[ 2] = timestr[ 6]; + timestr[ 3] = ' '; + timestr[ 4] = timestr[ 8]; + timestr[ 5] = timestr[ 9]; + timestr[ 6] = ' '; + if ( now - lsb.st_mtime > 60*60*24*182 ) /* 1/2 year */ + { + timestr[ 7] = ' '; + timestr[ 8] = timestr[20]; + timestr[ 9] = timestr[21]; + timestr[10] = timestr[22]; + timestr[11] = timestr[23]; + } + else + { + timestr[ 7] = timestr[11]; + timestr[ 8] = timestr[12]; + timestr[ 9] = ':'; + timestr[10] = timestr[14]; + timestr[11] = timestr[15]; + } + timestr[12] = '\0'; + + /* The ls -F file class. */ + switch ( sb.st_mode & S_IFMT ) + { + case S_IFDIR: fileclass = "/"; break; + case S_IFSOCK: fileclass = "="; break; + case S_IFLNK: fileclass = "@"; break; + default: + fileclass = ( sb.st_mode & S_IXOTH ) ? "*" : ""; + break; + } + + /* And print. */ + (void) fprintf( fp, + "%s %3ld %10lld %s %.80s%s%s%s\n", + modestr, (long) lsb.st_nlink, (long long) lsb.st_size, + timestr, encrname, S_ISDIR(sb.st_mode) ? "/" : "", + nameptrs[i], linkprefix, lnk, fileclass ); + } + + (void) fprintf( fp, "
\n \n\n" ); + (void) fclose( fp ); + exit( 0 ); + } + + /* Parent process. */ + closedir( dirp ); + syslog( LOG_DEBUG, "spawned indexing process %d for directory '%.200s'", r, hc->expnfilename ); +#ifdef CGI_TIMELIMIT + /* Schedule a kill for the child process, in case it runs too long */ + client_data.i = r; + if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(cgi_kill ls) failed" ); + exit( 1 ); + } +#endif /* CGI_TIMELIMIT */ + hc->status = 200; + hc->bytes_sent = CGI_BYTECOUNT; + hc->should_linger = 0; + } + else + { + closedir( dirp ); + httpd_send_err( + hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) ); + return -1; + } + + return 0; + } + +#endif /* GENERATE_INDEXES */ + + +static char* +build_env( char* fmt, char* arg ) + { + char* cp; + size_t size; + static char* buf; + static size_t maxbuf = 0; + + size = strlen( fmt ) + strlen( arg ); + if ( size > maxbuf ) + httpd_realloc_str( &buf, &maxbuf, size ); + (void) my_snprintf( buf, maxbuf, fmt, arg ); + cp = strdup( buf ); + if ( cp == (char*) 0 ) + { + syslog( LOG_ERR, "out of memory copying environment variable" ); + exit( 1 ); + } + return cp; + } + + +#ifdef SERVER_NAME_LIST +static char* +hostname_map( char* hostname ) + { + int len, n; + static char* list[] = { SERVER_NAME_LIST }; + + len = strlen( hostname ); + for ( n = sizeof(list) / sizeof(*list) - 1; n >= 0; --n ) + if ( strncasecmp( hostname, list[n], len ) == 0 ) + if ( list[n][len] == '/' ) /* check in case of a substring match */ + return &list[n][len + 1]; + return (char*) 0; + } +#endif /* SERVER_NAME_LIST */ + + +/* Set up environment variables. Be real careful here to avoid +** letting malicious clients overrun a buffer. We don't have +** to worry about freeing stuff since we're a sub-process. +*/ +static char** +make_envp( httpd_conn* hc ) + { + static char* envp[50]; + int envn; + char* cp; + char buf[256]; + + envn = 0; + envp[envn++] = build_env( "PATH=%s", CGI_PATH ); +#ifdef CGI_LD_LIBRARY_PATH + envp[envn++] = build_env( "LD_LIBRARY_PATH=%s", CGI_LD_LIBRARY_PATH ); +#endif /* CGI_LD_LIBRARY_PATH */ + envp[envn++] = build_env( "SERVER_SOFTWARE=%s", SERVER_SOFTWARE ); + if ( hc->hs->vhost && hc->hostname != (char*) 0 && hc->hostname[0] != '\0' ) + cp = hc->hostname; + else if ( hc->hdrhost != (char*) 0 && hc->hdrhost[0] != '\0' ) + cp = hc->hdrhost; + else if ( hc->reqhost != (char*) 0 && hc->reqhost[0] != '\0' ) + cp = hc->reqhost; + else + cp = hc->hs->server_hostname; + if ( cp != (char*) 0 ) + envp[envn++] = build_env( "SERVER_NAME=%s", cp ); + envp[envn++] = "GATEWAY_INTERFACE=CGI/1.1"; + envp[envn++] = build_env("SERVER_PROTOCOL=%s", hc->protocol); + (void) my_snprintf( buf, sizeof(buf), "%d", (int) hc->hs->port ); + envp[envn++] = build_env( "SERVER_PORT=%s", buf ); + envp[envn++] = build_env( + "REQUEST_METHOD=%s", httpd_method_str( hc->method ) ); + if ( hc->pathinfo[0] != '\0' ) + { + char* cp2; + size_t l; + envp[envn++] = build_env( "PATH_INFO=/%s", hc->pathinfo ); + l = strlen( hc->hs->cwd ) + strlen( hc->pathinfo ) + 1; + cp2 = NEW( char, l ); + if ( cp2 != (char*) 0 ) + { + (void) my_snprintf( cp2, l, "%s%s", hc->hs->cwd, hc->pathinfo ); + envp[envn++] = build_env( "PATH_TRANSLATED=%s", cp2 ); + } + } + envp[envn++] = build_env( + "SCRIPT_NAME=/%s", strcmp( hc->origfilename, "." ) == 0 ? + "" : hc->origfilename ); + if ( hc->query[0] != '\0') + envp[envn++] = build_env( "QUERY_STRING=%s", hc->query ); + envp[envn++] = build_env( + "REMOTE_ADDR=%s", httpd_ntoa( &hc->client_addr ) ); + if ( hc->referrer[0] != '\0' ) + { + envp[envn++] = build_env( "HTTP_REFERER=%s", hc->referrer ); + envp[envn++] = build_env( "HTTP_REFERRER=%s", hc->referrer ); + } + if ( hc->useragent[0] != '\0' ) + envp[envn++] = build_env( "HTTP_USER_AGENT=%s", hc->useragent ); + if ( hc->accept[0] != '\0' ) + envp[envn++] = build_env( "HTTP_ACCEPT=%s", hc->accept ); + if ( hc->accepte[0] != '\0' ) + envp[envn++] = build_env( "HTTP_ACCEPT_ENCODING=%s", hc->accepte ); + if ( hc->acceptl[0] != '\0' ) + envp[envn++] = build_env( "HTTP_ACCEPT_LANGUAGE=%s", hc->acceptl ); + if ( hc->cookie[0] != '\0' ) + envp[envn++] = build_env( "HTTP_COOKIE=%s", hc->cookie ); + if ( hc->contenttype[0] != '\0' ) + envp[envn++] = build_env( "CONTENT_TYPE=%s", hc->contenttype ); + if ( hc->hdrhost[0] != '\0' ) + envp[envn++] = build_env( "HTTP_HOST=%s", hc->hdrhost ); + if ( hc->contentlength != -1 ) + { + (void) my_snprintf( + buf, sizeof(buf), "%lu", (unsigned long) hc->contentlength ); + envp[envn++] = build_env( "CONTENT_LENGTH=%s", buf ); + } + if ( hc->remoteuser[0] != '\0' ) + envp[envn++] = build_env( "REMOTE_USER=%s", hc->remoteuser ); + if ( hc->authorization[0] != '\0' ) + envp[envn++] = build_env( "AUTH_TYPE=%s", "Basic" ); + /* We only support Basic auth at the moment. */ + if ( getenv( "TZ" ) != (char*) 0 ) + envp[envn++] = build_env( "TZ=%s", getenv( "TZ" ) ); + envp[envn++] = build_env( "CGI_PATTERN=%s", hc->hs->cgi_pattern ); + + envp[envn] = (char*) 0; + return envp; + } + + +/* Set up argument vector. Again, we don't have to worry about freeing stuff +** since we're a sub-process. This gets done after make_envp() because we +** scribble on hc->query. +*/ +static char** +make_argp( httpd_conn* hc ) + { + char** argp; + int argn; + char* cp1; + char* cp2; + + /* By allocating an arg slot for every character in the query, plus + ** one for the filename and one for the NULL, we are guaranteed to + ** have enough. We could actually use strlen/2. + */ + argp = NEW( char*, strlen( hc->query ) + 2 ); + if ( argp == (char**) 0 ) + return (char**) 0; + + argp[0] = strrchr( hc->expnfilename, '/' ); + if ( argp[0] != (char*) 0 ) + ++argp[0]; + else + argp[0] = hc->expnfilename; + + argn = 1; + /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html, + ** "The server should search the query information for a non-encoded = + ** character to determine if the command line is to be used, if it finds + ** one, the command line is not to be used." + */ + if ( strchr( hc->query, '=' ) == (char*) 0 ) + { + for ( cp1 = cp2 = hc->query; *cp2 != '\0'; ++cp2 ) + { + if ( *cp2 == '+' ) + { + *cp2 = '\0'; + strdecode( cp1, cp1 ); + argp[argn++] = cp1; + cp1 = cp2 + 1; + } + } + if ( cp2 != cp1 ) + { + strdecode( cp1, cp1 ); + argp[argn++] = cp1; + } + } + + argp[argn] = (char*) 0; + return argp; + } + + +/* This routine is used only for POST requests. It reads the data +** from the request and sends it to the child process. The only reason +** we need to do it this way instead of just letting the child read +** directly is that we have already read part of the data into our +** buffer. +*/ +static void +cgi_interpose_input( httpd_conn* hc, int wfd ) + { + size_t c; + ssize_t r; + char buf[1024]; + + c = hc->read_idx - hc->checked_idx; + if ( c > 0 ) + { + if ( httpd_write_fully( wfd, &(hc->read_buf[hc->checked_idx]), c ) != c ) + return; + } + while ( c < hc->contentlength ) + { + r = read( hc->conn_fd, buf, MIN( sizeof(buf), hc->contentlength - c ) ); + if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) + { + sleep( 1 ); + continue; + } + if ( r <= 0 ) + return; + if ( httpd_write_fully( wfd, buf, r ) != r ) + return; + c += r; + } + post_post_garbage_hack( hc ); + } + + +/* Special hack to deal with broken browsers that send a LF or CRLF +** after POST data, causing TCP resets - we just read and discard up +** to 2 bytes. Unfortunately this doesn't fix the problem for CGIs +** which avoid the interposer process due to their POST data being +** short. Creating an interposer process for all POST CGIs is +** unacceptably expensive. The eventual fix will come when interposing +** gets integrated into the main loop as a tasklet instead of a process. +*/ +static void +post_post_garbage_hack( httpd_conn* hc ) + { + char buf[2]; + + /* If we are in a sub-process, turn on no-delay mode in case we + ** previously cleared it. + */ + if ( sub_process ) + httpd_set_ndelay( hc->conn_fd ); + /* And read up to 2 bytes. */ + (void) read( hc->conn_fd, buf, sizeof(buf) ); + } + + +/* This routine is used for parsed-header CGIs. The idea here is that the +** CGI can return special headers such as "Status:" and "Location:" which +** change the return status of the response. Since the return status has to +** be the very first line written out, we have to accumulate all the headers +** and check for the special ones before writing the status. Then we write +** out the saved headers and proceed to echo the rest of the response. +*/ +static void +cgi_interpose_output( httpd_conn* hc, int rfd ) + { + int r; + char buf[1024]; + size_t headers_size, headers_len; + char* headers; + char* br; + int status; + char* title; + char* cp; + + /* Make sure the connection is in blocking mode. It should already + ** be blocking, but we might as well be sure. + */ + httpd_clear_ndelay( hc->conn_fd ); + + /* Slurp in all headers. */ + headers_size = 0; + httpd_realloc_str( &headers, &headers_size, 500 ); + headers_len = 0; + for (;;) + { + r = read( rfd, buf, sizeof(buf) ); + if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) + { + sleep( 1 ); + continue; + } + if ( r <= 0 ) + { + br = &(headers[headers_len]); + break; + } + httpd_realloc_str( &headers, &headers_size, headers_len + r ); + (void) memmove( &(headers[headers_len]), buf, r ); + headers_len += r; + headers[headers_len] = '\0'; + if ( ( br = strstr( headers, "\015\012\015\012" ) ) != (char*) 0 || + ( br = strstr( headers, "\012\012" ) ) != (char*) 0 ) + break; + } + + /* If there were no headers, bail. */ + if ( headers[0] == '\0' ) + return; + + /* Figure out the status. Look for a Status: or Location: header; + ** else if there's an HTTP header line, get it from there; else + ** default to 200. + */ + status = 200; + if ( strncmp( headers, "HTTP/", 5 ) == 0 ) + { + cp = headers; + cp += strcspn( cp, " \t" ); + status = atoi( cp ); + } + if ( ( cp = strstr( headers, "Location:" ) ) != (char*) 0 && + cp < br && + ( cp == headers || *(cp-1) == '\012' ) ) + status = 302; + if ( ( cp = strstr( headers, "Status:" ) ) != (char*) 0 && + cp < br && + ( cp == headers || *(cp-1) == '\012' ) ) + { + cp += 7; + cp += strspn( cp, " \t" ); + status = atoi( cp ); + } + + /* Write the status line. */ + switch ( status ) + { + case 200: title = ok200title; break; + case 302: title = err302title; break; + case 304: title = err304title; break; + case 400: title = httpd_err400title; break; +#ifdef AUTH_FILE + case 401: title = err401title; break; +#endif /* AUTH_FILE */ + case 403: title = err403title; break; + case 404: title = err404title; break; + case 408: title = httpd_err408title; break; + case 451: title = err451title; break; + case 500: title = err500title; break; + case 501: title = err501title; break; + case 503: title = httpd_err503title; break; + default: title = "Something"; break; + } + (void) my_snprintf( buf, sizeof(buf), "HTTP/1.0 %d %s\015\012", status, title ); + (void) httpd_write_fully( hc->conn_fd, buf, strlen( buf ) ); + + /* Write the saved headers. */ + (void) httpd_write_fully( hc->conn_fd, headers, headers_len ); + + /* Echo the rest of the output. */ + for (;;) + { + r = read( rfd, buf, sizeof(buf) ); + if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) + { + sleep( 1 ); + continue; + } + if ( r <= 0 ) + break; + if ( httpd_write_fully( hc->conn_fd, buf, r ) != r ) + break; + } + shutdown( hc->conn_fd, SHUT_WR ); + } + + +/* CGI child process. */ +static void +cgi_child( httpd_conn* hc ) + { + int r; + char** argp; + char** envp; + char* binary; + char* directory; + + /* Unset close-on-exec flag for this socket. This actually shouldn't + ** be necessary, according to POSIX a dup()'d file descriptor does + ** *not* inherit the close-on-exec flag, its flag is always clear. + ** However, Linux messes this up and does copy the flag to the + ** dup()'d descriptor, so we have to clear it. This could be + ** ifdeffed for Linux only. + */ + (void) fcntl( hc->conn_fd, F_SETFD, 0 ); + + /* Close the syslog descriptor so that the CGI program can't + ** mess with it. All other open descriptors should be either + ** the listen socket(s), sockets from accept(), or the file-logging + ** fd, and all of those are set to close-on-exec, so we don't + ** have to close anything else. + */ + closelog(); + + /* If the socket happens to be using one of the stdin/stdout/stderr + ** descriptors, move it to another descriptor so that the dup2 calls + ** below don't screw things up. We arbitrarily pick fd 3 - if there + ** was already something on it, we clobber it, but that doesn't matter + ** since at this point the only fd of interest is the connection. + ** All others will be closed on exec. + */ + if ( hc->conn_fd == STDIN_FILENO || hc->conn_fd == STDOUT_FILENO || hc->conn_fd == STDERR_FILENO ) + { + int newfd = dup2( hc->conn_fd, STDERR_FILENO + 1 ); + if ( newfd >= 0 ) + hc->conn_fd = newfd; + /* If the dup2 fails, shrug. We'll just take our chances. + ** Shouldn't happen though. + */ + } + + /* Make the environment vector. */ + envp = make_envp( hc ); + + /* Make the argument vector. */ + argp = make_argp( hc ); + + /* Set up stdin. For POSTs we may have to set up a pipe from an + ** interposer process, depending on if we've read some of the data + ** into our buffer. + */ + if ( hc->method == METHOD_POST && hc->read_idx > hc->checked_idx ) + { + int p[2]; + + if ( pipe( p ) < 0 ) + { + syslog( LOG_ERR, "pipe - %m" ); + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + httpd_write_response( hc ); + exit( 1 ); + } + r = fork( ); + if ( r < 0 ) + { + syslog( LOG_ERR, "fork - %m" ); + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + httpd_write_response( hc ); + exit( 1 ); + } + if ( r == 0 ) + { + /* Interposer process. */ + sub_process = 1; + (void) close( p[0] ); + cgi_interpose_input( hc, p[1] ); + exit( 0 ); + } + /* Need to schedule a kill for process r; but in the main process! */ + (void) close( p[1] ); + if ( p[0] != STDIN_FILENO ) + { + (void) dup2( p[0], STDIN_FILENO ); + (void) close( p[0] ); + } + } + else + { + /* Otherwise, the request socket is stdin. */ + if ( hc->conn_fd != STDIN_FILENO ) + (void) dup2( hc->conn_fd, STDIN_FILENO ); + } + + /* Set up stdout/stderr. If we're doing CGI header parsing, + ** we need an output interposer too. + */ + if ( strncmp( argp[0], "nph-", 4 ) != 0 && hc->mime_flag ) + { + int p[2]; + + if ( pipe( p ) < 0 ) + { + syslog( LOG_ERR, "pipe - %m" ); + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + httpd_write_response( hc ); + exit( 1 ); + } + r = fork( ); + if ( r < 0 ) + { + syslog( LOG_ERR, "fork - %m" ); + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + httpd_write_response( hc ); + exit( 1 ); + } + if ( r == 0 ) + { + /* Interposer process. */ + sub_process = 1; + (void) close( p[1] ); + cgi_interpose_output( hc, p[0] ); + exit( 0 ); + } + /* Need to schedule a kill for process r; but in the main process! */ + (void) close( p[0] ); + if ( p[1] != STDOUT_FILENO ) + (void) dup2( p[1], STDOUT_FILENO ); + if ( p[1] != STDERR_FILENO ) + (void) dup2( p[1], STDERR_FILENO ); + if ( p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO ) + (void) close( p[1] ); + } + else + { + /* Otherwise, the request socket is stdout/stderr. */ + if ( hc->conn_fd != STDOUT_FILENO ) + (void) dup2( hc->conn_fd, STDOUT_FILENO ); + if ( hc->conn_fd != STDERR_FILENO ) + (void) dup2( hc->conn_fd, STDERR_FILENO ); + } + + /* At this point we would like to set close-on-exec again for hc->conn_fd + ** (see previous comments on Linux's broken behavior re: close-on-exec + ** and dup.) Unfortunately there seems to be another Linux problem, or + ** perhaps a different aspect of the same problem - if we do this + ** close-on-exec in Linux, the socket stays open but stderr gets + ** closed - the last fd duped from the socket. What a mess. So we'll + ** just leave the socket as is, which under other OSs means an extra + ** file descriptor gets passed to the child process. Since the child + ** probably already has that file open via stdin stdout and/or stderr, + ** this is not a problem. + */ + /* (void) fcntl( hc->conn_fd, F_SETFD, 1 ); */ + +#ifdef CGI_NICE + /* Set priority. */ + (void) nice( CGI_NICE ); +#endif /* CGI_NICE */ + + /* Split the program into directory and binary, so we can chdir() + ** to the program's own directory. This isn't in the CGI 1.1 + ** spec, but it's what other HTTP servers do. + */ + directory = strdup( hc->expnfilename ); + if ( directory == (char*) 0 ) + binary = hc->expnfilename; /* ignore errors */ + else + { + binary = strrchr( directory, '/' ); + if ( binary == (char*) 0 ) + binary = hc->expnfilename; + else + { + *binary++ = '\0'; + (void) chdir( directory ); /* ignore errors */ + } + } + + /* Default behavior for SIGPIPE. */ +#ifdef HAVE_SIGSET + (void) sigset( SIGPIPE, SIG_DFL ); +#else /* HAVE_SIGSET */ + (void) signal( SIGPIPE, SIG_DFL ); +#endif /* HAVE_SIGSET */ + + /* Run the program. */ + (void) execve( binary, argp, envp ); + + /* Something went wrong. */ + syslog( LOG_ERR, "execve %.80s - %m", hc->expnfilename ); + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + httpd_write_response( hc ); + _exit( 1 ); + } + + +static int +cgi( httpd_conn* hc ) + { + int r; + ClientData client_data; + + if ( hc->method == METHOD_GET || hc->method == METHOD_POST ) + { + if ( hc->hs->cgi_limit != 0 && hc->hs->cgi_count >= hc->hs->cgi_limit ) + { + httpd_send_err( + hc, 503, httpd_err503title, "", httpd_err503form, + hc->encodedurl ); + return -1; + } + ++hc->hs->cgi_count; + httpd_clear_ndelay( hc->conn_fd ); + r = fork( ); + if ( r < 0 ) + { + syslog( LOG_ERR, "fork - %m" ); + httpd_send_err( + hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + if ( r == 0 ) + { + /* Child process. */ + sub_process = 1; + httpd_unlisten( hc->hs ); + cgi_child( hc ); + } + + /* Parent process. */ + syslog( LOG_DEBUG, "spawned CGI process %d for file '%.200s'", r, hc->expnfilename ); +#ifdef CGI_TIMELIMIT + /* Schedule a kill for the child process, in case it runs too long */ + client_data.i = r; + if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(cgi_kill child) failed" ); + exit( 1 ); + } +#endif /* CGI_TIMELIMIT */ + hc->status = 200; + hc->bytes_sent = CGI_BYTECOUNT; + hc->should_linger = 0; + } + else + { + httpd_send_err( + hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) ); + return -1; + } + + return 0; + } + + +static int +really_start_request( httpd_conn* hc, struct timeval* nowP ) + { + static char* indexname; + static size_t maxindexname = 0; + static const char* index_names[] = { INDEX_NAMES }; + int i; +#ifdef AUTH_FILE + static char* dirname; + static size_t maxdirname = 0; +#endif /* AUTH_FILE */ + size_t expnlen, indxlen; + char* cp; + char* pi; + + expnlen = strlen( hc->expnfilename ); + + if ( hc->method != METHOD_GET && hc->method != METHOD_HEAD && + hc->method != METHOD_POST ) + { + httpd_send_err( + hc, 501, err501title, "", err501form, httpd_method_str( hc->method ) ); + return -1; + } + + /* Stat the file. */ + if ( stat( hc->expnfilename, &hc->sb ) < 0 ) + { + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + + /* Is it world-readable or world-executable? We check explicitly instead + ** of just trying to open it, so that no one ever gets surprised by + ** a file that's not set world-readable and yet somehow is + ** readable by the HTTP server and therefore the *whole* world. + */ + if ( ! ( hc->sb.st_mode & ( S_IROTH | S_IXOTH ) ) ) + { + syslog( + LOG_INFO, + "%.80s URL \"%.80s\" resolves to a non world-readable file", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file that is not world-readable.\n" ), + hc->encodedurl ); + return -1; + } + + /* Is it a directory? */ + if ( S_ISDIR(hc->sb.st_mode) ) + { + /* If there's pathinfo, it's just a non-existent file. */ + if ( hc->pathinfo[0] != '\0' ) + { + httpd_send_err( hc, 404, err404title, "", err404form, hc->encodedurl ); + return -1; + } + + /* Special handling for directory URLs that don't end in a slash. + ** We send back an explicit redirect with the slash, because + ** otherwise many clients can't build relative URLs properly. + */ + if ( strcmp( hc->origfilename, "" ) != 0 && + strcmp( hc->origfilename, "." ) != 0 && + hc->origfilename[strlen( hc->origfilename ) - 1] != '/' ) + { + send_dirredirect( hc ); + return -1; + } + + /* Check for an index file. */ + for ( i = 0; i < sizeof(index_names) / sizeof(char*); ++i ) + { + httpd_realloc_str( + &indexname, &maxindexname, + expnlen + 1 + strlen( index_names[i] ) ); + (void) strcpy( indexname, hc->expnfilename ); + indxlen = strlen( indexname ); + if ( indxlen == 0 || indexname[indxlen - 1] != '/' ) + (void) strcat( indexname, "/" ); + if ( strcmp( indexname, "./" ) == 0 ) + indexname[0] = '\0'; + (void) strcat( indexname, index_names[i] ); + if ( stat( indexname, &hc->sb ) >= 0 ) + goto got_one; + } + + /* Nope, no index file, so it's an actual directory request. */ +#ifdef GENERATE_INDEXES + /* Directories must be readable for indexing. */ + if ( ! ( hc->sb.st_mode & S_IROTH ) ) + { + syslog( + LOG_INFO, + "%.80s URL \"%.80s\" tried to index a directory with indexing disabled", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a directory that has indexing disabled.\n" ), + hc->encodedurl ); + return -1; + } +#ifdef AUTH_FILE + /* Check authorization for this directory. */ + if ( auth_check( hc, hc->expnfilename ) == -1 ) + return -1; +#endif /* AUTH_FILE */ + /* Referrer check. */ + if ( ! check_referrer( hc ) ) + return -1; + /* Ok, generate an index. */ + return ls( hc ); +#else /* GENERATE_INDEXES */ + syslog( + LOG_INFO, "%.80s URL \"%.80s\" tried to index a directory", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' is a directory, and directory indexing is disabled on this server.\n" ), + hc->encodedurl ); + return -1; +#endif /* GENERATE_INDEXES */ + + got_one: ; + /* Got an index file. Expand symlinks again. More pathinfo means + ** something went wrong. + */ + cp = expand_symlinks( indexname, &pi, hc->hs->no_symlink_check, hc->tildemapped ); + if ( cp == (char*) 0 || pi[0] != '\0' ) + { + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + expnlen = strlen( cp ); + httpd_realloc_str( &hc->expnfilename, &hc->maxexpnfilename, expnlen ); + (void) strcpy( hc->expnfilename, cp ); + + /* Now, is the index version world-readable or world-executable? */ + if ( ! ( hc->sb.st_mode & ( S_IROTH | S_IXOTH ) ) ) + { + syslog( + LOG_INFO, + "%.80s URL \"%.80s\" resolves to a non-world-readable index file", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' resolves to an index file that is not world-readable.\n" ), + hc->encodedurl ); + return -1; + } + } + +#ifdef AUTH_FILE + /* Check authorization for this directory. */ + httpd_realloc_str( &dirname, &maxdirname, expnlen ); + (void) strcpy( dirname, hc->expnfilename ); + cp = strrchr( dirname, '/' ); + if ( cp == (char*) 0 ) + (void) strcpy( dirname, "." ); + else + *cp = '\0'; + if ( auth_check( hc, dirname ) == -1 ) + return -1; + + /* Check if the filename is the AUTH_FILE itself - that's verboten. */ + if ( expnlen == sizeof(AUTH_FILE) - 1 ) + { + if ( strcmp( hc->expnfilename, AUTH_FILE ) == 0 ) + { + syslog( + LOG_NOTICE, + "%.80s URL \"%.80s\" tried to retrieve an auth file", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' is an authorization file, retrieving it is not permitted.\n" ), + hc->encodedurl ); + return -1; + } + } + else if ( expnlen >= sizeof(AUTH_FILE) && + strcmp( &(hc->expnfilename[expnlen - sizeof(AUTH_FILE) + 1]), AUTH_FILE ) == 0 && + hc->expnfilename[expnlen - sizeof(AUTH_FILE)] == '/' ) + { + syslog( + LOG_NOTICE, + "%.80s URL \"%.80s\" tried to retrieve an auth file", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' is an authorization file, retrieving it is not permitted.\n" ), + hc->encodedurl ); + return -1; + } +#endif /* AUTH_FILE */ + + /* Referrer check. */ + if ( ! check_referrer( hc ) ) + return -1; + + /* Is it world-executable and in the CGI area? */ + if ( hc->hs->cgi_pattern != (char*) 0 && + ( hc->sb.st_mode & S_IXOTH ) && + match( hc->hs->cgi_pattern, hc->expnfilename ) ) + return cgi( hc ); + + /* It's not CGI. If it's executable or there's pathinfo, someone's + ** trying to either serve or run a non-CGI file as CGI. Either case + ** is prohibited. + */ + if ( hc->sb.st_mode & S_IXOTH ) + { + syslog( + LOG_NOTICE, "%.80s URL \"%.80s\" is executable but isn't CGI", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file which is marked executable but is not a CGI file; retrieving it is forbidden.\n" ), + hc->encodedurl ); + return -1; + } + if ( hc->pathinfo[0] != '\0' ) + { + syslog( + LOG_INFO, "%.80s URL \"%.80s\" has pathinfo but isn't CGI", + httpd_ntoa( &hc->client_addr ), hc->encodedurl ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "The requested URL '%.80s' resolves to a file plus CGI-style pathinfo, but the file is not a valid CGI file.\n" ), + hc->encodedurl ); + return -1; + } + + /* Fill in last_byte_index, if necessary. */ + if ( hc->got_range && + ( hc->last_byte_index == -1 || hc->last_byte_index >= hc->sb.st_size ) ) + hc->last_byte_index = hc->sb.st_size - 1; + + figure_mime( hc ); + + if ( hc->method == METHOD_HEAD ) + { + send_mime( + hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size, + hc->sb.st_mtime ); + } + else if ( hc->if_modified_since != (time_t) -1 && + hc->if_modified_since >= hc->sb.st_mtime ) + { + send_mime( + hc, 304, err304title, hc->encodings, "", hc->type, (off_t) -1, + hc->sb.st_mtime ); + } + else + { + hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP ); + if ( hc->file_address == (char*) 0 ) + { + httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); + return -1; + } + send_mime( + hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size, + hc->sb.st_mtime ); + } + + return 0; + } + + +int +httpd_start_request( httpd_conn* hc, struct timeval* nowP ) + { + int r; + + /* Really start the request. */ + r = really_start_request( hc, nowP ); + + /* And return the status. */ + return r; + } + + +static void +make_log_entry( httpd_conn* hc, struct timeval* nowP ) + { + char* ru; + char url[305]; + char bytes[40]; + + if ( hc->hs->no_log ) + return; + + /* This is straight CERN Combined Log Format - the only tweak + ** being that if we're using syslog() we leave out the date, because + ** syslogd puts it in. The included syslogtocern script turns the + ** results into true CERN format. + */ + + /* Format remote user. */ + if ( hc->remoteuser[0] != '\0' ) + ru = hc->remoteuser; + else + ru = "-"; + /* If we're vhosting, prepend the hostname to the url. This is + ** a little weird, perhaps writing separate log files for + ** each vhost would make more sense. + */ + if ( hc->hs->vhost && ! hc->tildemapped ) + (void) my_snprintf( url, sizeof(url), + "/%.100s%.200s", + hc->hostname == (char*) 0 ? hc->hs->server_hostname : hc->hostname, + hc->encodedurl ); + else + (void) my_snprintf( url, sizeof(url), + "%.200s", hc->encodedurl ); + /* Format the bytes. */ + if ( hc->bytes_sent >= 0 ) + (void) my_snprintf( + bytes, sizeof(bytes), "%lld", (long long) hc->bytes_sent ); + else + (void) strcpy( bytes, "-" ); + + /* Logfile or syslog? */ + if ( hc->hs->logfp != (FILE*) 0 ) + { + time_t now; + struct tm* t; + const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S"; + char date_nozone[100]; + int zone; + char sign; + char date[100]; + + /* Get the current time, if necessary. */ + if ( nowP != (struct timeval*) 0 ) + now = nowP->tv_sec; + else + now = time( (time_t*) 0 ); + /* Format the time, forcing a numeric timezone (some log analyzers + ** are stoooopid about this). + */ + t = localtime( &now ); + (void) strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t ); +#ifdef HAVE_TM_GMTOFF + zone = t->tm_gmtoff / 60L; +#else + zone = -timezone / 60L; + /* Probably have to add something about daylight time here. */ +#endif + if ( zone >= 0 ) + sign = '+'; + else + { + sign = '-'; + zone = -zone; + } + zone = ( zone / 60 ) * 100 + zone % 60; + (void) my_snprintf( date, sizeof(date), + "%s %c%04d", date_nozone, sign, zone ); + /* And write the log entry. */ + (void) fprintf( hc->hs->logfp, + "%.80s - %.80s [%s] \"%.80s %.300s %.80s\" %d %s \"%.200s\" \"%.200s\"\n", + httpd_ntoa( &hc->client_addr ), ru, date, + httpd_method_str( hc->method ), url, hc->protocol, + hc->status, bytes, hc->referrer, hc->useragent ); +#ifdef FLUSH_LOG_EVERY_TIME + (void) fflush( hc->hs->logfp ); +#endif + } + else + syslog( LOG_INFO, + "%.80s - %.80s \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.200s\"", + httpd_ntoa( &hc->client_addr ), ru, + httpd_method_str( hc->method ), url, hc->protocol, + hc->status, bytes, hc->referrer, hc->useragent ); + } + + +/* Returns 1 if ok to serve the url, 0 if not. */ +static int +check_referrer( httpd_conn* hc ) + { + int r; + char* cp; + + /* Are we doing referrer checking at all? */ + if ( hc->hs->url_pattern == (char*) 0 ) + return 1; + + r = really_check_referrer( hc ); + + if ( ! r ) + { + if ( hc->hs->vhost && hc->hostname != (char*) 0 ) + cp = hc->hostname; + else + cp = hc->hs->server_hostname; + if ( cp == (char*) 0 ) + cp = ""; + syslog( + LOG_INFO, "%.80s non-local referrer \"%.80s%.80s\" \"%.80s\"", + httpd_ntoa( &hc->client_addr ), cp, hc->encodedurl, hc->referrer ); + httpd_send_err( + hc, 403, err403title, "", + ERROR_FORM( err403form, "You must supply a local referrer to get URL '%.80s' from this server.\n" ), + hc->encodedurl ); + } + return r; + } + + +/* Returns 1 if ok to serve the url, 0 if not. */ +static int +really_check_referrer( httpd_conn* hc ) + { + httpd_server* hs; + char* cp1; + char* cp2; + char* cp3; + static char* refhost = (char*) 0; + static size_t refhost_size = 0; + char *lp; + + hs = hc->hs; + + /* Check for an empty referrer. */ + if ( hc->referrer == (char*) 0 || hc->referrer[0] == '\0' || + ( cp1 = strstr( hc->referrer, "//" ) ) == (char*) 0 ) + { + /* Disallow if we require a referrer and the url matches. */ + if ( hs->no_empty_referrers && match( hs->url_pattern, hc->origfilename ) ) + return 0; + /* Otherwise ok. */ + return 1; + } + + /* Extract referrer host. */ + cp1 += 2; + for ( cp2 = cp1; *cp2 != '/' && *cp2 != ':' && *cp2 != '\0'; ++cp2 ) + continue; + httpd_realloc_str( &refhost, &refhost_size, cp2 - cp1 ); + for ( cp3 = refhost; cp1 < cp2; ++cp1, ++cp3 ) + if ( isupper(*cp1) ) + *cp3 = tolower(*cp1); + else + *cp3 = *cp1; + *cp3 = '\0'; + + /* Local pattern? */ + if ( hs->local_pattern != (char*) 0 ) + lp = hs->local_pattern; + else + { + /* No local pattern. What's our hostname? */ + if ( ! hs->vhost ) + { + /* Not vhosting, use the server name. */ + lp = hs->server_hostname; + if ( lp == (char*) 0 ) + /* Couldn't figure out local hostname - give up. */ + return 1; + } + else + { + /* We are vhosting, use the hostname on this connection. */ + lp = hc->hostname; + if ( lp == (char*) 0 ) + /* Oops, no hostname. Maybe it's an old browser that + ** doesn't send a Host: header. We could figure out + ** the default hostname for this IP address, but it's + ** not worth it for the few requests like this. + */ + return 1; + } + } + + /* If the referrer host doesn't match the local host pattern, and + ** the filename does match the url pattern, it's an illegal reference. + */ + if ( ! match( lp, refhost ) && match( hs->url_pattern, hc->origfilename ) ) + return 0; + /* Otherwise ok. */ + return 1; + } + + +char* +httpd_ntoa( httpd_sockaddr* saP ) + { +#ifdef USE_IPV6 + static char str[200]; + + if ( getnameinfo( &saP->sa, sockaddr_len( saP ), str, sizeof(str), 0, 0, NI_NUMERICHOST ) != 0 ) + { + str[0] = '?'; + str[1] = '\0'; + } + else if ( IN6_IS_ADDR_V4MAPPED( &saP->sa_in6.sin6_addr ) && strncmp( str, "::ffff:", 7 ) == 0 ) + /* Elide IPv6ish prefix for IPv4 addresses. */ + (void) ol_strcpy( str, &str[7] ); + + return str; + +#else /* USE_IPV6 */ + + return inet_ntoa( saP->sa_in.sin_addr ); + +#endif /* USE_IPV6 */ + } + + +static int +sockaddr_check( httpd_sockaddr* saP ) + { + switch ( saP->sa.sa_family ) + { + case AF_INET: return 1; +#ifdef USE_IPV6 + case AF_INET6: return 1; +#endif /* USE_IPV6 */ + default: + return 0; + } + } + + +static size_t +sockaddr_len( httpd_sockaddr* saP ) + { + switch ( saP->sa.sa_family ) + { + case AF_INET: return sizeof(struct sockaddr_in); +#ifdef USE_IPV6 + case AF_INET6: return sizeof(struct sockaddr_in6); +#endif /* USE_IPV6 */ + default: + return 0; /* shouldn't happen */ + } + } + + +/* Some systems don't have snprintf(), so we make our own that uses +** either vsnprintf() or vsprintf(). If your system doesn't have +** vsnprintf(), it is probably vulnerable to buffer overruns. +** Upgrade! +*/ +static int +my_snprintf( char* str, size_t size, const char* format, ... ) + { + va_list ap; + int r; + + va_start( ap, format ); +#ifdef HAVE_VSNPRINTF + r = vsnprintf( str, size, format, ap ); +#else /* HAVE_VSNPRINTF */ + r = vsprintf( str, format, ap ); +#endif /* HAVE_VSNPRINTF */ + va_end( ap ); + return r; + } + + +#ifndef HAVE_ATOLL +static long long +atoll( const char* str ) + { + long long value; + long long sign; + + while ( isspace( *str ) ) + ++str; + switch ( *str ) + { + case '-': sign = -1; ++str; break; + case '+': sign = 1; ++str; break; + default: sign = 1; break; + } + value = 0; + while ( isdigit( *str ) ) + { + value = value * 10 + ( *str - '0' ); + ++str; + } + return sign * value; + } +#endif /* HAVE_ATOLL */ + + +/* Read the requested buffer completely, accounting for interruptions. */ +int +httpd_read_fully( int fd, void* buf, size_t nbytes ) + { + int nread; + + nread = 0; + while ( nread < nbytes ) + { + int r; + + r = read( fd, (char*) buf + nread, nbytes - nread ); + if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) + { + sleep( 1 ); + continue; + } + if ( r < 0 ) + return r; + if ( r == 0 ) + break; + nread += r; + } + + return nread; + } + + +/* Write the requested buffer completely, accounting for interruptions. */ +int +httpd_write_fully( int fd, const char* buf, size_t nbytes ) + { + int nwritten; + + nwritten = 0; + while ( nwritten < nbytes ) + { + int r; + + r = write( fd, buf + nwritten, nbytes - nwritten ); + if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) + { + sleep( 1 ); + continue; + } + if ( r < 0 ) + return r; + if ( r == 0 ) + break; + nwritten += r; + } + + return nwritten; + } + + +/* Generate debugging statistics syslog message. */ +void +httpd_logstats( long secs ) + { + if ( str_alloc_count > 0 ) + syslog( LOG_NOTICE, + " libhttpd - %d strings allocated, %lu bytes (%g bytes/str)", + str_alloc_count, (unsigned long) str_alloc_size, + (float) str_alloc_size / str_alloc_count ); + } diff --git a/src/thttpd-2.27/libhttpd.h b/src/thttpd-2.27/libhttpd.h new file mode 100644 index 0000000..7805546 --- /dev/null +++ b/src/thttpd-2.27/libhttpd.h @@ -0,0 +1,288 @@ +/* libhttpd.h - defines for libhttpd +** +** Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer . +** 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 +#include +#include +#include +#include +#include +#include + +#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 + +/* States for checked_state. */ +#define CHST_FIRSTWORD 0 +#define CHST_FIRSTWS 1 +#define CHST_SECONDWORD 2 +#define CHST_SECONDWS 3 +#define CHST_THIRDWORD 4 +#define CHST_THIRDWS 5 +#define CHST_LINE 6 +#define CHST_LF 7 +#define CHST_CR 8 +#define CHST_CRLF 9 +#define CHST_CRLFCR 10 +#define CHST_BOGUS 11 + + +/* Initializes. Does the socket(), bind(), and listen(). Returns an +** httpd_server* which includes a socket fd that you can select() on. +** Return (httpd_server*) 0 on error. +*/ +httpd_server* httpd_initialize( + char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, + unsigned short port, char* cgi_pattern, int cgi_limit, char* charset, + char* p3p, int max_age, char* cwd, int no_log, FILE* logfp, + int no_symlink_check, int vhost, int global_passwd, char* url_pattern, + char* local_pattern, int no_empty_referrers ); + +/* Change the log file. */ +void httpd_set_logfp( httpd_server* hs, FILE* logfp ); + +/* Call to unlisten/close socket(s) listening for new connections. */ +void httpd_unlisten( httpd_server* hs ); + +/* Call to shut down. */ +void httpd_terminate( httpd_server* hs ); + + +/* When a listen fd is ready to read, call this. It does the accept() and +** returns an httpd_conn* which includes the fd to read the request from and +** write the response to. Returns an indication of whether the accept() +** failed, succeeded, or if there were no more connections to accept. +** +** In order to minimize malloc()s, the caller passes in the httpd_conn. +** The caller is also responsible for setting initialized to zero before the +** first call using each different httpd_conn. +*/ +int httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc ); +#define GC_FAIL 0 +#define GC_OK 1 +#define GC_NO_MORE 2 + +/* Checks whether the data in hc->read_buf constitutes a complete request +** yet. The caller reads data into hc->read_buf[hc->read_idx] and advances +** hc->read_idx. This routine checks what has been read so far, using +** hc->checked_idx and hc->checked_state to keep track, and returns an +** indication of whether there is no complete request yet, there is a +** complete request, or there won't be a valid request due to a syntax error. +*/ +int httpd_got_request( httpd_conn* hc ); +#define GR_NO_REQUEST 0 +#define GR_GOT_REQUEST 1 +#define GR_BAD_REQUEST 2 + +/* Parses the request in hc->read_buf. Fills in lots of fields in hc, +** like the URL and the various headers. +** +** Returns -1 on error. +*/ +int httpd_parse_request( httpd_conn* hc ); + +/* Starts sending data back to the client. In some cases (directories, +** CGI programs), finishes sending by itself - in those cases, hc->file_fd +** is <0. If there is more data to be sent, then hc->file_fd is a file +** descriptor for the file to send. If you don't have a current timeval +** handy just pass in 0. +** +** Returns -1 on error. +*/ +int httpd_start_request( httpd_conn* hc, struct timeval* nowP ); + +/* Actually sends any buffered response text. */ +void httpd_write_response( httpd_conn* hc ); + +/* Call this to close down a connection and free the data. A fine point, +** if you fork() with a connection open you should still call this in the +** parent process - the connection will stay open in the child. +** If you don't have a current timeval handy just pass in 0. +*/ +void httpd_close_conn( httpd_conn* hc, struct timeval* nowP ); + +/* Call this to de-initialize a connection struct and *really* free the +** mallocced strings. +*/ +void httpd_destroy_conn( httpd_conn* hc ); + + +/* Send an error message back to the client. */ +void httpd_send_err( + httpd_conn* hc, int status, char* title, char* extraheads, char* form, + char* arg ); + +/* Some error messages. */ +extern char* httpd_err400title; +extern char* httpd_err400form; +extern char* httpd_err408title; +extern char* httpd_err408form; +extern char* httpd_err503title; +extern char* httpd_err503form; + +/* Generate a string representation of a method number. */ +char* httpd_method_str( int method ); + +/* Reallocate a string. */ +void httpd_realloc_str( char** strP, size_t* maxsizeP, size_t size ); + +/* Format a network socket to a string representation. */ +char* httpd_ntoa( httpd_sockaddr* saP ); + +/* Set NDELAY mode on a socket. */ +void httpd_set_ndelay( int fd ); + +/* Clear NDELAY mode on a socket. */ +void httpd_clear_ndelay( int fd ); + +/* Read the requested buffer completely, accounting for interruptions. */ +int httpd_read_fully( int fd, void* buf, size_t nbytes ); + +/* Write the requested buffer completely, accounting for interruptions. */ +int httpd_write_fully( int fd, const char* buf, size_t nbytes ); + +/* Generate debugging statistics syslog message. */ +void httpd_logstats( long secs ); + +#endif /* _LIBHTTPD_H_ */ diff --git a/src/thttpd-2.27/match.c b/src/thttpd-2.27/match.c new file mode 100644 index 0000000..6facccb --- /dev/null +++ b/src/thttpd-2.27/match.c @@ -0,0 +1,88 @@ +/* match.c - simple shell-style filename matcher +** +** Only does ? * and **, and multiple patterns separated by |. Returns 1 or 0. +** +** Copyright © 1995,2000 by Jef Poskanzer . +** 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 + +#include "match.h" + +static int match_one( const char* pattern, int patternlen, const char* string ); + +int +match( const char* pattern, const char* string ) + { + const char* or; + + for (;;) + { + or = strchr( pattern, '|' ); + if ( or == (char*) 0 ) + return match_one( pattern, strlen( pattern ), string ); + if ( match_one( pattern, or - pattern, string ) ) + return 1; + pattern = or + 1; + } + } + + +static int +match_one( const char* pattern, int patternlen, const char* string ) + { + const char* p; + + for ( p = pattern; p - pattern < patternlen; ++p, ++string ) + { + if ( *p == '?' && *string != '\0' ) + continue; + if ( *p == '*' ) + { + int i, pl; + ++p; + if ( *p == '*' ) + { + /* Double-wildcard matches anything. */ + ++p; + i = strlen( string ); + } + else + /* Single-wildcard matches anything but slash. */ + i = strcspn( string, "/" ); + pl = patternlen - ( p - pattern ); + for ( ; i >= 0; --i ) + if ( match_one( p, pl, &(string[i]) ) ) + return 1; + return 0; + } + if ( *p != *string ) + return 0; + } + if ( *string == '\0' ) + return 1; + return 0; + } diff --git a/src/thttpd-2.27/match.h b/src/thttpd-2.27/match.h new file mode 100644 index 0000000..01c5f2a --- /dev/null +++ b/src/thttpd-2.27/match.h @@ -0,0 +1,36 @@ +/* match.h - simple shell-style filename patcher +** +** Copyright © 1995 by Jef Poskanzer . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#ifndef _MATCH_H_ +#define _MATCH_H_ + +/* Simple shell-style filename pattern matcher. Only does ? * and **, and +** multiple patterns separated by |. Returns 1 or 0. +*/ +int match( const char* pattern, const char* string ); + +#endif /* _MATCH_H_ */ diff --git a/src/thttpd-2.27/mime_encodings.txt b/src/thttpd-2.27/mime_encodings.txt new file mode 100644 index 0000000..2d3952d --- /dev/null +++ b/src/thttpd-2.27/mime_encodings.txt @@ -0,0 +1,8 @@ +# mime_encodings.txt +# +# A list of file extensions followed by the corresponding MIME encoding. +# Extensions not found in the table proceed to the mime_types table. + +Z compress +gz gzip +uu x-uuencode diff --git a/src/thttpd-2.27/mime_types.txt b/src/thttpd-2.27/mime_types.txt new file mode 100644 index 0000000..d4725d9 --- /dev/null +++ b/src/thttpd-2.27/mime_types.txt @@ -0,0 +1,198 @@ +# mime_types.txt +# +# A list of file extensions followed by the corresponding MIME type. +# Extensions not found in the table are returned as text/plain. + +a application/octet-stream +aab application/x-authorware-bin +aam application/x-authorware-map +aas application/x-authorware-seg +ai application/postscript +aif audio/x-aiff +aifc audio/x-aiff +aiff audio/x-aiff +asc text/plain; charset=%s +asf video/x-ms-asf +asx video/x-ms-asf +au audio/basic +avi video/x-msvideo +bcpio application/x-bcpio +bin application/octet-stream +bmp image/bmp +cdf application/x-netcdf +class application/x-java-vm +cpio application/x-cpio +cpt application/mac-compactpro +crl application/x-pkcs7-crl +crt application/x-x509-ca-cert +csh application/x-csh +css text/css; charset=%s +dcr application/x-director +dir application/x-director +djv image/vnd.djvu +djvu image/vnd.djvu +dll application/octet-stream +dms application/octet-stream +doc application/msword +dtd text/xml; charset=%s +dump application/octet-stream +dvi application/x-dvi +dxr application/x-director +eps application/postscript +etx text/x-setext +exe application/octet-stream +ez application/andrew-inset +fgd application/x-director +fh image/x-freehand +fh4 image/x-freehand +fh5 image/x-freehand +fh7 image/x-freehand +fhc image/x-freehand +gif image/gif +gtar application/x-gtar +hdf application/x-hdf +hqx application/mac-binhex40 +htm text/html; charset=%s +html text/html; charset=%s +ice x-conference/x-cooltalk +ief image/ief +iges model/iges +igs model/iges +iv application/x-inventor +jar application/x-java-archive +jfif image/jpeg +jpe image/jpeg +jpeg image/jpeg +jpg image/jpeg +js application/x-javascript +kar audio/midi +kml application/vnd.google-earth.kml+xml +kmz application/vnd.google-earth.kmz +latex application/x-latex +lha application/octet-stream +loc application/xml-loc +lzh application/octet-stream +m3u audio/x-mpegurl +man application/x-troff-man +mathml application/mathml+xml +me application/x-troff-me +mesh model/mesh +mid audio/midi +midi audio/midi +mif application/vnd.mif +mime message/rfc822 +mml application/mathml+xml +mov video/quicktime +movie video/x-sgi-movie +mp2 audio/mpeg +mp3 audio/mpeg +mp4 video/mp4 +mpe video/mpeg +mpeg video/mpeg +mpg video/mpeg +mpga audio/mpeg +ms application/x-troff-ms +msh model/mesh +mv video/x-sgi-movie +mxu video/vnd.mpegurl +nc application/x-netcdf +o application/octet-stream +oda application/oda +ogg application/ogg +pac application/x-ns-proxy-autoconfig +pbm image/x-portable-bitmap +pdb chemical/x-pdb +pdf application/pdf +pgm image/x-portable-graymap +pgn application/x-chess-pgn +png image/png +pnm image/x-portable-anymap +ppm image/x-portable-pixmap +ppt application/vnd.ms-powerpoint +ps application/postscript +qt video/quicktime +ra audio/x-realaudio +ram audio/x-pn-realaudio +ras image/x-cmu-raster +rdf application/rdf+xml +rgb image/x-rgb +rm audio/x-pn-realaudio +roff application/x-troff +rpm audio/x-pn-realaudio-plugin +rss application/rss+xml +rtf text/rtf; charset=%s +rtx text/richtext; charset=%s +sgm text/sgml; charset=%s +sgml text/sgml; charset=%s +sh application/x-sh +shar application/x-shar +silo model/mesh +sit application/x-stuffit +skd application/x-koan +skm application/x-koan +skp application/x-koan +skt application/x-koan +smi application/smil +smil application/smil +snd audio/basic +so application/octet-stream +spl application/x-futuresplash +src application/x-wais-source +stc application/vnd.sun.xml.calc.template +std application/vnd.sun.xml.draw.template +sti application/vnd.sun.xml.impress.template +stw application/vnd.sun.xml.writer.template +sv4cpio application/x-sv4cpio +sv4crc application/x-sv4crc +svg image/svg+xml +svgz image/svg+xml +swf application/x-shockwave-flash +sxc application/vnd.sun.xml.calc +sxd application/vnd.sun.xml.draw +sxg application/vnd.sun.xml.writer.global +sxi application/vnd.sun.xml.impress +sxm application/vnd.sun.xml.math +sxw application/vnd.sun.xml.writer +t application/x-troff +tar application/x-tar +tcl application/x-tcl +tex application/x-tex +texi application/x-texinfo +texinfo application/x-texinfo +tif image/tiff +tiff image/tiff +tr application/x-troff +tsp application/dsptype +tsv text/tab-separated-values; charset=%s +txt text/plain; charset=%s +ustar application/x-ustar +vcd application/x-cdlink +vrml model/vrml +vx video/x-rad-screenplay +wav audio/x-wav +wax audio/x-ms-wax +wbmp image/vnd.wap.wbmp +wbxml application/vnd.wap.wbxml +wm video/x-ms-wm +wma audio/x-ms-wma +wmd application/x-ms-wmd +wml text/vnd.wap.wml +wmlc application/vnd.wap.wmlc +wmls text/vnd.wap.wmlscript +wmlsc application/vnd.wap.wmlscriptc +wmv video/x-ms-wmv +wmx video/x-ms-wmx +wmz application/x-ms-wmz +wrl model/vrml +wsrc application/x-wais-source +wvx video/x-ms-wvx +xbm image/x-xbitmap +xht application/xhtml+xml; charset=%s +xhtml application/xhtml+xml; charset=%s +xls application/vnd.ms-excel +xml text/xml; charset=%s +xpm image/x-xpixmap +xsl text/xml; charset=%s +xwd image/x-xwindowdump +xyz chemical/x-xyz +zip application/zip diff --git a/src/thttpd-2.27/mmc.c b/src/thttpd-2.27/mmc.c new file mode 100644 index 0000000..3e81259 --- /dev/null +++ b/src/thttpd-2.27/mmc.c @@ -0,0 +1,531 @@ +/* mmc.c - mmap cache +** +** Copyright © 1998,2001,2014 by Jef Poskanzer . +** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_MMAP +#include +#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: %ld", + alloc_count, map_count, (long long) mapped_bytes, free_count, hash_size, + expire_age ); + if ( map_count + free_count != alloc_count ) + syslog( LOG_ERR, "map counts don't add up!" ); + } diff --git a/src/thttpd-2.27/mmc.h b/src/thttpd-2.27/mmc.h new file mode 100644 index 0000000..7ca0448 --- /dev/null +++ b/src/thttpd-2.27/mmc.h @@ -0,0 +1,55 @@ +/* mmc.h - header file for mmap cache package +** +** Copyright © 1998,2014 by Jef Poskanzer . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#ifndef _MMC_H_ +#define _MMC_H_ + +/* Returns an mmap()ed area for the given file, or (void*) 0 on errors. +** If you have a stat buffer on the file, pass it in, otherwise pass 0. +** Same for the current time. +*/ +void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP ); + +/* Done with an mmap()ed area that was returned by mmc_map(). +** If you have a stat buffer on the file, pass it in, otherwise pass 0. +** Same for the current time. +*/ +void mmc_unmap( void* addr, struct stat* sbP, struct timeval* nowP ); + +/* Clean up the mmc package, freeing any unused storage. +** This should be called periodically, say every five minutes. +** If you have the current time, pass it in, otherwise pass 0. +*/ +void mmc_cleanup( struct timeval* nowP ); + +/* Free all storage, usually in preparation for exitting. */ +void mmc_term( void ); + +/* Generate debugging statistics syslog message. */ +void mmc_logstats( long secs ); + +#endif /* _MMC_H_ */ diff --git a/src/thttpd-2.27/scripts/500.thttpd-rotate b/src/thttpd-2.27/scripts/500.thttpd-rotate new file mode 100755 index 0000000..a172b83 --- /dev/null +++ b/src/thttpd-2.27/scripts/500.thttpd-rotate @@ -0,0 +1,19 @@ +#!/bin/sh +# +# thttpd-rotate - nightly script to rotate thttpd's log files on FreeBSD +# +# This goes in /etc/periodic/daily. It rotates the log files and then +# tells thttpd to re-open its log file. + +cd /usr/local/www/chroot/logs +rm -f thttpd_log.7.gz +mv thttpd_log.6.gz thttpd_log.7.gz +mv thttpd_log.5.gz thttpd_log.6.gz +mv thttpd_log.4.gz thttpd_log.5.gz +mv thttpd_log.3.gz thttpd_log.4.gz +mv thttpd_log.2.gz thttpd_log.3.gz +mv thttpd_log.1.gz thttpd_log.2.gz +mv thttpd_log thttpd_log.1 +kill -HUP `cat /var/run/thttpd.pid` +sleep 1 +gzip -f thttpd_log.1 diff --git a/src/thttpd-2.27/scripts/thttpd.sh b/src/thttpd-2.27/scripts/thttpd.sh new file mode 100755 index 0000000..43bac4b --- /dev/null +++ b/src/thttpd-2.27/scripts/thttpd.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# +# thttpd.sh - startup script for thttpd on FreeBSD +# +# This goes in /usr/local/etc/rc.d and gets run at boot-time. +# +# Variables available: +# thttpd_enable='YES/NO' +# thttpd_program='path' +# thttpd_pidfile='path' +# thttpd_devfs='path' +# +# PROVIDE: thttpd +# REQUIRE: LOGIN FILESYSTEMS +# KEYWORD: shutdown + +. /etc/rc.subr + +name='thttpd' +rcvar='thttpd_enable' + +load_rc_config "$name" + +# Defaults. +thttpd_enable="${thttpd_enable:-'NO'}" +thttpd_program="${thttpd_program:-'/usr/local/sbin/thttpd'}" +thttpd_pidfile="${thttpd_pidfile:-'/var/run/thttpd.pid'}" + +thttpd_precmd () + { + if [ '' != "$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"` + } + +command="$thttpd_program" +pidfile="$thttpd_pidfile" +start_precmd='thttpd_precmd' +stop_cmd='thttpd_stop' + +run_rc_command "$1" diff --git a/src/thttpd-2.27/scripts/thttpd_wrapper b/src/thttpd-2.27/scripts/thttpd_wrapper new file mode 100755 index 0000000..631c34d --- /dev/null +++ b/src/thttpd-2.27/scripts/thttpd_wrapper @@ -0,0 +1,23 @@ +#!/bin/sh +# +# thttpd_wrapper - wrapper script for thttpd on FreeBSD +# +# This goes in /usr/local/sbin. It backgrounds itself, and then runs +# thttpd in a loop. If thttpd exits then the script restarts it automatically. +# +# The -D flag tells thttpd to *not* put itself into the background, +# and the -C flag tells it to get the rest of its configuration from +# the specified config file. + +( + while true ; do + /usr/local/sbin/thttpd -D -C /usr/local/www/thttpd_config + if [ -f /var/run/nologin ] ; then + exit + fi + sleep 10 + egrep ' thttpd[:\[]' /var/log/messages | + tail -33 | + mail -s "thttpd on `hostname` restarted" root + done +) & diff --git a/src/thttpd-2.27/strerror.c b/src/thttpd-2.27/strerror.c new file mode 100644 index 0000000..6a161e6 --- /dev/null +++ b/src/thttpd-2.27/strerror.c @@ -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 + +#include + +char * +strerror(errnum) + int errnum; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + static char ebuf[20]; + + if ((unsigned int)errnum < sys_nerr) + return(sys_errlist[errnum]); + (void)sprintf(ebuf, "Unknown error: %d", errnum); + return(ebuf); +} diff --git a/src/thttpd-2.27/tdate_parse.c b/src/thttpd-2.27/tdate_parse.c new file mode 100644 index 0000000..a7ea7fa --- /dev/null +++ b/src/thttpd-2.27/tdate_parse.c @@ -0,0 +1,328 @@ +/* tdate_parse - parse string dates into internal form, stripped-down version +** +** Copyright © 1995 by Jef Poskanzer . +** 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 + +#include +#ifdef HAVE_MEMORY_H +#include +#endif +#include +#include +#include +#include + +#include "tdate_parse.h" + + +struct strlong { + char* s; + long l; + }; + + +static void +pound_case( char* str ) + { + for ( ; *str != '\0'; ++str ) + { + if ( isupper( (int) *str ) ) + *str = tolower( (int) *str ); + } + } + + +static int +strlong_compare( const void* v1, const void* v2 ) + { + const struct strlong* s1 = (const struct strlong*) v1; + const struct strlong* s2 = (const struct strlong*) v2; + return strcmp( s1->s, s2->s ); + } + + +static int +strlong_search( char* str, struct strlong* tab, int n, long* lP ) + { + int i, h, l, r; + + l = 0; + h = n - 1; + for (;;) + { + i = ( h + l ) / 2; + r = strcmp( str, tab[i].s ); + if ( r < 0 ) + h = i - 1; + else if ( r > 0 ) + l = i + 1; + else + { + *lP = tab[i].l; + return 1; + } + if ( h < l ) + return 0; + } + } + + +static int +scan_wday( char* str_wday, long* tm_wdayP ) + { + static struct strlong wday_tab[] = { + { "sun", 0 }, { "sunday", 0 }, + { "mon", 1 }, { "monday", 1 }, + { "tue", 2 }, { "tuesday", 2 }, + { "wed", 3 }, { "wednesday", 3 }, + { "thu", 4 }, { "thursday", 4 }, + { "fri", 5 }, { "friday", 5 }, + { "sat", 6 }, { "saturday", 6 }, + }; + static int sorted = 0; + + if ( ! sorted ) + { + (void) qsort( + wday_tab, sizeof(wday_tab)/sizeof(struct strlong), + sizeof(struct strlong), strlong_compare ); + sorted = 1; + } + pound_case( str_wday ); + return strlong_search( + str_wday, wday_tab, sizeof(wday_tab)/sizeof(struct strlong), tm_wdayP ); + } + + +static int +scan_mon( char* str_mon, long* tm_monP ) + { + static struct strlong mon_tab[] = { + { "jan", 0 }, { "january", 0 }, + { "feb", 1 }, { "february", 1 }, + { "mar", 2 }, { "march", 2 }, + { "apr", 3 }, { "april", 3 }, + { "may", 4 }, + { "jun", 5 }, { "june", 5 }, + { "jul", 6 }, { "july", 6 }, + { "aug", 7 }, { "august", 7 }, + { "sep", 8 }, { "september", 8 }, + { "oct", 9 }, { "october", 9 }, + { "nov", 10 }, { "november", 10 }, + { "dec", 11 }, { "december", 11 }, + }; + static int sorted = 0; + + if ( ! sorted ) + { + (void) qsort( + mon_tab, sizeof(mon_tab)/sizeof(struct strlong), + sizeof(struct strlong), strlong_compare ); + sorted = 1; + } + pound_case( str_mon ); + return strlong_search( + str_mon, mon_tab, sizeof(mon_tab)/sizeof(struct strlong), tm_monP ); + } + + +static int +is_leap( int year ) + { + return year % 400? ( year % 100 ? ( year % 4 ? 0 : 1 ) : 0 ) : 1; + } + + +/* Basically the same as mktime(). */ +static time_t +tm_to_time( struct tm* tmP ) + { + time_t t; + static int monthtab[12] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + /* Years since epoch, converted to days. */ + t = ( tmP->tm_year - 70 ) * 365; + /* Leap days for previous years - this will break in 2100! */ + t += ( tmP->tm_year - 69 ) / 4; + /* Days for the beginning of this month. */ + t += monthtab[tmP->tm_mon]; + /* Leap day for this year. */ + if ( tmP->tm_mon >= 2 && is_leap( tmP->tm_year + 1900 ) ) + ++t; + /* Days since the beginning of this month. */ + t += tmP->tm_mday - 1; /* 1-based field */ + /* Hours, minutes, and seconds. */ + t = t * 24 + tmP->tm_hour; + t = t * 60 + tmP->tm_min; + t = t * 60 + tmP->tm_sec; + + return t; + } + + +time_t +tdate_parse( char* str ) + { + struct tm tm; + char* cp; + char str_mon[500], str_wday[500]; + int tm_sec, tm_min, tm_hour, tm_mday, tm_year; + long tm_mon, tm_wday; + time_t t; + + /* Initialize. */ + (void) memset( (char*) &tm, 0, sizeof(struct tm) ); + + /* Skip initial whitespace ourselves - sscanf is clumsy at this. */ + for ( cp = str; *cp == ' ' || *cp == '\t'; ++cp ) + continue; + + /* And do the sscanfs. WARNING: you can add more formats here, + ** but be careful! You can easily screw up the parsing of existing + ** formats when you add new ones. The order is important. + */ + + /* DD-mth-YY HH:MM:SS GMT */ + if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT", + &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec ) == 6 && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } + + /* DD mth YY HH:MM:SS GMT */ + else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT", + &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec) == 6 && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } + + /* HH:MM:SS GMT DD-mth-YY */ + else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d", + &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, + &tm_year ) == 6 && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + } + + /* HH:MM:SS GMT DD mth YY */ + else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d", + &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, + &tm_year ) == 6 && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + } + + /* wdy, DD-mth-YY HH:MM:SS GMT */ + else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT", + str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec ) == 7 && + scan_wday( str_wday, &tm_wday ) && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_wday = tm_wday; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } + + /* wdy, DD mth YY HH:MM:SS GMT */ + else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT", + str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec ) == 7 && + scan_wday( str_wday, &tm_wday ) && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_wday = tm_wday; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } + + /* wdy mth DD HH:MM:SS GMT YY */ + else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d", + str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec, + &tm_year ) == 7 && + scan_wday( str_wday, &tm_wday ) && + scan_mon( str_mon, &tm_mon ) ) + { + tm.tm_wday = tm_wday; + tm.tm_mon = tm_mon; + tm.tm_mday = tm_mday; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_year = tm_year; + } + else + return (time_t) -1; + + if ( tm.tm_year > 1900 ) + tm.tm_year -= 1900; + else if ( tm.tm_year < 70 ) + tm.tm_year += 100; + + t = tm_to_time( &tm ); + + return t; + } diff --git a/src/thttpd-2.27/tdate_parse.h b/src/thttpd-2.27/tdate_parse.h new file mode 100644 index 0000000..aaf0b66 --- /dev/null +++ b/src/thttpd-2.27/tdate_parse.h @@ -0,0 +1,33 @@ +/* tdate_parse.h - parse string dates into internal form, stripped-down version +** +** Copyright © 1995 by Jef Poskanzer . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#ifndef _TDATE_PARSE_H_ +#define _TDATE_PARSE_H_ + +time_t tdate_parse( char* str ); + +#endif /* _TDATE_PARSE_H_ */ diff --git a/src/thttpd-2.27/thttpd.8 b/src/thttpd-2.27/thttpd.8 new file mode 100644 index 0000000..040f74c --- /dev/null +++ b/src/thttpd-2.27/thttpd.8 @@ -0,0 +1,596 @@ +.TH thttpd 8 "29 February 2000" +.SH NAME +thttpd - tiny/turbo/throttling HTTP server +.SH SYNOPSIS +.B thttpd +.RB [ -C +.IR configfile ] +.RB [ -p +.IR port ] +.RB [ -d +.IR dir ] +.RB [ -dd +.IR data_dir ] +.RB [ -r | -nor ] +.RB [ -s | -nos ] +.RB [ -v | -nov ] +.RB [ -g | -nog ] +.RB [ -u +.IR user ] +.RB [ -c +.IR cgipat ] +.RB [ -t +.IR throttles ] +.RB [ -h +.IR host ] +.RB [ -l +.IR logfile ] +.RB [ -i +.IR pidfile ] +.RB [ -T +.IR charset ] +.RB [ -P +.IR P3P ] +.RB [ -M +.IR maxage ] +.RB [ -V ] +.RB [ -D ] +.SH DESCRIPTION +.PP +.I thttpd +is a simple, small, fast, and secure HTTP server. +It doesn't have a lot of special features, but it suffices for most uses of +the web, it's about as fast as the best full-featured servers (Apache, NCSA, +Netscape), +and it has one extremely useful feature (URL-traffic-based throttling) +that no other server currently has. +.SH OPTIONS +.TP +.B -C +Specifies a config-file to read. +All options can be set either by command-line flags or in the config file. +See below for details. +.TP +.B -p +Specifies an alternate port number to listen on. +The default is 80. +The config-file option name for this flag is "port", +and the config.h option is DEFAULT_PORT. +.TP +.B -d +Specifies a directory to chdir() to at startup. +This is merely a convenience - you could just as easily +do a cd in the shell script that invokes the program. +The config-file option name for this flag is "dir", +and the config.h options are WEBDIR, USE_USER_DIR. +.TP +.B -r +Do a chroot() at initialization time, restricting file access +to the program's current directory. +If -r is the compiled-in default, then -nor disables it. +See below for details. +The config-file option names for this flag are "chroot" and "nochroot", +and the config.h option is ALWAYS_CHROOT. +.TP +.B -dd +Specifies a directory to chdir() to after chrooting. +If you're not chrooting, you might as well do a single chdir() with +the -d flag. +If you are chrooting, this lets you put the web files in a subdirectory +of the chroot tree, instead of in the top level mixed in with the +chroot files. +The config-file option name for this flag is "data_dir". +.TP +.B -nos +Don't do explicit symbolic link checking. +Normally, thttpd explicitly expands any symbolic links in filenames, +to check that the resulting path stays within the original document tree. +If you want to turn off this check and save some CPU time, you can use +the -nos flag, however this is not recommended. +Note, though, that if you are using the chroot option, the symlink +checking is unnecessary and is turned off, so the safe way to save +those CPU cycles is to use chroot. +The config-file option names for this flag are "symlinkcheck" and "nosymlinkcheck". +.TP +.B -v +Do el-cheapo virtual hosting. +If -v is the compiled-in default, then -nov disables it. +See below for details. +The config-file option names for this flag are "vhost" and "novhost", +and the config.h option is ALWAYS_VHOST. +.TP +.B -g +Use a global passwd file. +This means that every file in the entire document tree is protected by +the single .htpasswd file at the top of the tree. +Otherwise the semantics of the .htpasswd file are the same. +If this option is set but there is no .htpasswd file in +the top-level directory, then thttpd proceeds as if the option was +not set - first looking for a local .htpasswd file, and if that doesn't +exist either then serving the file without any password. +If -g is the compiled-in default, then -nog disables it. +The config-file option names for this flag are "globalpasswd" and +"noglobalpasswd", +and the config.h option is ALWAYS_GLOBAL_PASSWD. +.TP +.B -u +Specifies what user to switch to after initialization when started as root. +The default is "nobody". +The config-file option name for this flag is "user", +and the config.h option is DEFAULT_USER. +.TP +.B -c +Specifies a wildcard pattern for CGI programs, for instance "**.cgi" +or "/cgi-bin/*". +See below for details. +The config-file option name for this flag is "cgipat", +and the config.h option is CGI_PATTERN. +.TP +.B -t +Specifies a file of throttle settings. +See below for details. +The config-file option name for this flag is "throttles". +.TP +.B -h +Specifies a hostname to bind to, for multihoming. +The default is to bind to all hostnames supported on the local machine. +See below for details. +The config-file option name for this flag is "host", +and the config.h option is SERVER_NAME. +.TP +.B -l +Specifies a file for logging. +If no -l argument is specified, thttpd logs via syslog(). +If "-l /dev/null" is specified, thttpd doesn't log at all. +The config-file option name for this flag is "logfile". +.TP +.B -i +Specifies a file to write the process-id to. +If no file is specified, no process-id is written. +You can use this file to send signals to thttpd. +See below for details. +The config-file option name for this flag is "pidfile". +.TP +.B -T +Specifies the character set to use with text MIME types. +The default is UTF-8. +The config-file option name for this flag is "charset", +and the config.h option is DEFAULT_CHARSET. +.TP +.B -P +Specifies a P3P server privacy header to be returned with all responses. +See http://www.w3.org/P3P/ for details. +Thttpd doesn't do anything at all with the string except put it in the +P3P: response header. +The config-file option name for this flag is "p3p". +.TP +.B -M +Specifies the number of seconds to be used in a "Cache-Control: max-age" +header to be returned with all responses. +An equivalent "Expires" header is also generated. +The default is no Cache-Control or Expires headers, +which is just fine for most sites. +The config-file option name for this flag is "max_age". +.TP +.B -V +Shows the current version info. +.TP +.B -D +This was originally just a debugging flag, however it's worth mentioning +because one of the things it does is prevent thttpd from making itself +a background daemon. +Instead it runs in the foreground like a regular program. +This is necessary when you want to run thttpd wrapped in a little shell +script that restarts it if it exits. +.SH "CONFIG-FILE" +.PP +All the command-line options can also be set in a config file. +One advantage of using a config file is that the file can be changed, +and thttpd will pick up the changes with a restart. +.PP +The syntax of the config file is simple, a series of "option" or +"option=value" separated by whitespace. +The option names are listed above with their corresponding command-line flags. +.SH "CHROOT" +.PP +chroot() is a system call that restricts the program's view +of the filesystem to the current directory and directories +below it. +It becomes impossible for remote users to access any file +outside of the initial directory. +The restriction is inherited by child processes, so CGI programs get it too. +This is a very strong security measure, and is recommended. +The only downside is that only root can call chroot(), so this means +the program must be started as root. +However, the last thing it does during initialization is to +give up root access by becoming another user, so this is safe. +.PP +The program can also be compile-time configured to always +do a chroot(), without needing the -r flag. +.PP +Note that with some other web servers, such as NCSA httpd, setting +up a directory tree for use with chroot() is complicated, involving +creating a bunch of special directories and copying in various files. +With thttpd it's a lot easier, all you have to do is make sure +any shells, utilities, and config files used by your CGI programs and +scripts are available. +If you have CGI disabled, or if you make a policy that all CGI programs +must be written in a compiled language such as C and statically linked, +then you probably don't have to do any setup at all. +.PP +However, one thing you should do is tell syslogd about the chroot tree, +so that thttpd can still generate syslog messages. +Check your system's syslodg man page for how to do this. +In FreeBSD you would put something like this in /etc/rc.conf: +.nf + syslogd_flags="-l /usr/local/www/data/dev/log" +.fi +Substitute in your own chroot tree's pathname, of course. +Don't worry about creating the log socket, syslogd wants to do that itself. +(You may need to create the dev directory.) +In Linux the flag is -a instead of -l, and there may be other differences. +.PP +Relevant config.h option: ALWAYS_CHROOT. +.SH "CGI" +.PP +thttpd supports the CGI 1.1 spec. +.PP +In order for a CGI program to be run, its name must match the pattern +specified either at compile time or on the command line with the -c flag. +This is a simple shell-style filename pattern. +You can use * to match any string not including a slash, +or ** to match any string including slashes, +or ? to match any single character. +You can also use multiple such patterns separated by |. +The patterns get checked against the filename +part of the incoming URL. +Don't forget to quote any wildcard characters so that the shell doesn't +mess with them. +.PP +Restricting CGI programs to a single directory lets the site administrator +review them for security holes, and is strongly recommended. +If there are individual users that you trust, you can enable their +directories too. +.PP +If no CGI pattern is specified, neither here nor at compile time, +then CGI programs cannot be run at all. +If you want to disable CGI as a security measure, that's how you do it, just +comment out the patterns in the config file and don't run with the -c flag. +.PP +Note: the current working directory when a CGI program gets run is +the directory that the CGI program lives in. +This isn't in the CGI 1.1 spec, but it's what most other HTTP servers do. +.PP +Relevant config.h options: CGI_PATTERN, CGI_TIMELIMIT, CGI_NICE, CGI_PATH, CGI_LD_LIBRARY_PATH, CGIBINDIR. +.SH "BASIC AUTHENTICATION" +.PP +Basic Authentication is available as an option at compile time. +If enabled, it uses a password file in the directory to be protected, +called .htpasswd by default. +This file is formatted as the familiar colon-separated +username/encrypted-password pair, records delimited by newlines. +The protection does not carry over to subdirectories. +The utility program htpasswd(1) is included to help create and +modify .htpasswd files. +.PP +Relevant config.h option: AUTH_FILE +.SH "THROTTLING" +.PP +The throttle file lets you set maximum byte rates on URLs or URL groups. +You can optionally set a minimum rate too. +The format of the throttle file is very simple. +A # starts a comment, and the rest of the line is ignored. +Blank lines are ignored. +The rest of the lines should consist of a pattern, whitespace, and a number. +The pattern is a simple shell-style filename pattern, using ?/**/*, or +multiple such patterns separated by |. +.PP +The numbers in the file are byte rates, specified in units of bytes per second. +For comparison, a v.90 modem gives about 5000 B/s depending on compression, +a double-B-channel ISDN line about 12800 B/s, and a T1 line is about +150000 B/s. +If you want to set a minimum rate as well, use number-number. +.PP +Example: +.nf + # throttle file for www.acme.com + + ** 2000-100000 # limit total web usage to 2/3 of our T1, + # but never go below 2000 B/s + **.jpg|**.gif 50000 # limit images to 1/3 of our T1 + **.mpg 20000 # and movies to even less + jef/** 20000 # jef's pages are too popular +.fi +.PP +Throttling is implemented by checking each incoming URL filename against all +of the patterns in the throttle file. +The server accumulates statistics on how much bandwidth each pattern +has accounted for recently (via a rolling average). +If a URL matches a pattern that has been exceeding its specified limit, +then the data returned is actually slowed down, with +pauses between each block. +If that's not possible (e.g. for CGI programs) or if the bandwidth has gotten +way larger than the limit, then the server returns a special code +saying 'try again later'. +.PP +The minimum rates are implemented similarly. +If too many people are trying to fetch something at the same time, +throttling may slow down each connection so much that it's not really +useable. +Furthermore, all those slow connections clog up the server, using +up file handles and connection slots. +Setting a minimum rate says that past a certain point you should not +even bother - the server returns the 'try again later" code and the +connection isn't even started. +.PP +There is no provision for setting a maximum connections/second throttle, +because throttling a request uses as much cpu as handling it, so +there would be no point. +There is also no provision for throttling the number of simultaneous +connections on a per-URL basis. +However you can control the overall number of connections for the whole +server very simply, by setting the operating system's per-process file +descriptor limit before starting thttpd. +Be sure to set the hard limit, not the soft limit. +.SH "MULTIHOMING" +.PP +Multihoming means using one machine to serve multiple hostnames. +For instance, if you're an internet provider and you want to let +all of your customers have customized web addresses, you might +have www.joe.acme.com, www.jane.acme.com, and your own www.acme.com, +all running on the same physical hardware. +This feature is also known as "virtual hosts". +There are three steps to setting this up. +.PP +One, make DNS entries for all of the hostnames. +The current way to do this, allowed by HTTP/1.1, is to use CNAME aliases, +like so: +.nf + www.acme.com IN A 192.100.66.1 + www.joe.acme.com IN CNAME www.acme.com + www.jane.acme.com IN CNAME www.acme.com +.fi +However, this is incompatible with older HTTP/1.0 browsers. +If you want to stay compatible, there's a different way - use A records +instead, each with a different IP address, like so: +.nf + www.acme.com IN A 192.100.66.1 + www.joe.acme.com IN A 192.100.66.200 + www.jane.acme.com IN A 192.100.66.201 +.fi +This is bad because it uses extra IP addresses, a somewhat scarce resource. +But if you want people with older browsers to be able to visit your +sites, you still have to do it this way. +.PP +Step two. +If you're using the modern CNAME method of multihoming, then you can +skip this step. +Otherwise, using the older multiple-IP-address method you +must set up IP aliases or multiple interfaces for the extra addresses. +You can use ifconfig(8)'s alias command to tell the machine to answer to +all of the different IP addresses. +Example: +.nf + ifconfig le0 www.acme.com + ifconfig le0 www.joe.acme.com alias + ifconfig le0 www.jane.acme.com alias +.fi +If your OS's version of ifconfig doesn't have an alias command, you're +probably out of luck (but see http://www.acme.com/software/thttpd/notes.html). +.PP +Third and last, you must set up thttpd to handle the multiple hosts. +The easiest way is with the -v flag, or the ALWAYS_VHOST config.h option. +This works with either CNAME multihosting or multiple-IP multihosting. +What it does is send each incoming request to a subdirectory based on the +hostname it's intended for. +All you have to do in order to set things up is to create those subdirectories +in the directory where thttpd will run. +With the example above, you'd do like so: +.nf + mkdir www.acme.com www.joe.acme.com www.jane.acme.com +.fi +If you're using old-style multiple-IP multihosting, you should also create +symbolic links from the numeric addresses to the names, like so: +.nf + ln -s www.acme.com 192.100.66.1 + ln -s www.joe.acme.com 192.100.66.200 + ln -s www.jane.acme.com 192.100.66.201 +.fi +This lets the older HTTP/1.0 browsers find the right subdirectory. +.PP +There's an optional alternate step three if you're using multiple-IP +multihosting: run a separate thttpd process for each hostname, using +the -h flag to specify which one is which. +This gives you more flexibility, since you can run each of these processes +in separate directories, with different throttle files, etc. +Example: +.nf + thttpd -r -d /usr/www -h www.acme.com + thttpd -r -d /usr/www/joe -u joe -h www.joe.acme.com + thttpd -r -d /usr/www/jane -u jane -h www.jane.acme.com +.fi +But remember, this multiple-process method does not work with CNAME +multihosting - for that, you must use a single thttpd process with +the -v flag. +.SH "CUSTOM ERRORS" +.PP +thttpd lets you define your own custom error pages for the various +HTTP errors. +There's a separate file for each error number, all stored in one +special directory. +The directory name is "errors", at the top of the web directory tree. +The error files should be named "errNNN.html", where NNN is the error number. +So for example, to make a custom error page for the authentication failure +error, which is number 401, you would put your HTML into the file +"errors/err401.html". +If no custom error file is found for a given error number, then the +usual built-in error page is generated. +.PP +If you're using the virtual hosts option, you can also have different +custom error pages for each different virtual host. +In this case you put another "errors" directory in the top of that +virtual host's web tree. +thttpd will look first in the virtual host errors directory, and +then in the server-wide errors directory, and if neither of those +has an appropriate error file then it will generate the built-in error. +.SH "NON-LOCAL REFERRERS" +.PP +Sometimes another site on the net will embed your image files in their +HTML files, which basically means they're stealing your bandwidth. +You can prevent them from doing this by using non-local referrer filtering. +With this option, certain files can only be fetched via a local referrer. +The files have to be referenced by a local web page. +If a web page on some other site references the files, that fetch will +be blocked. +There are three config-file variables for this feature: +.TP +.B urlpat +A wildcard pattern for the URLs that should require a local referrer. +This is typically just image files, sound files, and so on. +For example: +.nf + urlpat=**.jpg|**.gif|**.au|**.wav +.fi +For most sites, that one setting is all you need to enable referrer filtering. +.TP +.B noemptyreferrers +By default, requests with no referrer at all, or a null referrer, or a +referrer with no apparent hostname, are allowed. +With this variable set, such requests are disallowed. +.TP +.B localpat +A wildcard pattern that specifies the local host or hosts. +This is used to determine if the host in the referrer is local or not. +If not specified it defaults to the actual local hostname. +.SH SYMLINKS +.PP +thttpd is very picky about symbolic links. +Before delivering any file, it first checks each element in the path +to see if it's a symbolic link, and expands them all out to get the final +actual filename. +Along the way it checks for things like links with ".." that go above +the server's directory, and absolute symlinks (ones that start with a /). +These are prohibited as security holes, so the server returns an +error page for them. +This means you can't set up your web directory with a bunch of symlinks +pointing to individual users' home web directories. +Instead you do it the other way around - the user web directories are +real subdirs of the main web directory, and in each user's home +dir there's a symlink pointing to their actual web dir. +.PP +The CGI pattern is also affected - it gets matched against the fully-expanded +filename. So, if you have a single CGI directory but then put a symbolic +link in it pointing somewhere else, that won't work. The CGI program will be +treated as a regular file and returned to the client, instead of getting run. +This could be confusing. +.SH PERMISSIONS +.PP +thttpd is also picky about file permissions. +It wants data files (HTML, images) to be world readable. +Readable by the group that the thttpd process runs as is not enough - thttpd +checks explicitly for the world-readable bit. +This is so that no one ever gets surprised by a file that's not set +world-readable and yet somehow is readable by the HTTP server and +therefore the *whole* world. +.PP +The same logic applies to directories. +As with the standard Unix "ls" program, thttpd will only let you +look at the contents of a directory if its read bit is on; but +as with data files, this must be the world-read bit, not just the +group-read bit. +.PP +thttpd also wants the execute bit to be *off* for data files. +A file that is marked executable but doesn't match the CGI pattern +might be a script or program that got accidentally left in the +wrong directory. +Allowing people to fetch the contents of the file might be a security breach, +so this is prohibited. +Of course if an executable file *does* match the CGI pattern, then it +just gets run as a CGI. +.PP +In summary, data files should be mode 644 (rw-r--r--), +directories should be 755 (rwxr-xr-x) if you want to allow indexing and +711 (rwx--x--x) to disallow it, and CGI programs should be mode +755 (rwxr-xr-x) or 711 (rwx--x--x). +.SH LOGS +.PP +thttpd does all of its logging via syslog(3). +The facility it uses is configurable. +Aside from error messages, there are only a few log entry types of interest, +all fairly similar to CERN Common Log Format: +.nf + Aug 6 15:40:34 acme thttpd[583]: 165.113.207.103 - - "GET /file" 200 357 + Aug 6 15:40:43 acme thttpd[583]: 165.113.207.103 - - "HEAD /file" 200 0 + Aug 6 15:41:16 acme thttpd[583]: referrer http://www.acme.com/ -> /dir + Aug 6 15:41:16 acme thttpd[583]: user-agent Mozilla/1.1N +.fi +The package includes a script for translating these log entries info +CERN-compatible files. +Note that thttpd does not translate numeric IP addresses into domain names. +This is both to save time and as a minor security measure (the numeric +address is harder to spoof). +.PP +Relevant config.h option: LOG_FACILITY. +.PP +If you'd rather log directly to a file, you can use the -l command-line +flag. But note that error messages still go to syslog. +.SH SIGNALS +.PP +thttpd handles a couple of signals, which you can send via the +standard Unix kill(1) command: +.TP +.B INT,TERM +These signals tell thttpd to shut down immediately. +Any requests in progress get aborted. +.TP +.B USR1 +This signal tells thttpd to shut down as soon as it's done servicing +all current requests. +In addition, the network socket it uses to accept new connections gets +closed immediately, which means a fresh thttpd can be started up +immediately. +.TP +.B USR2 +This signal tells thttpd to generate the statistics syslog messages +immediately, instead of waiting for the regular hourly update. +.TP +.B HUP +This signal tells thttpd to close and re-open its (non-syslog) log file, +for instance if you rotated the logs and want it to start using the +new one. +This is a little tricky to set up correctly, for instance if you are using +chroot() then the log file must be within the chroot tree, but it's +definitely doable. +.SH "SEE ALSO" +redirect(8), ssi(8), makeweb(1), htpasswd(1), syslogtocern(8), weblog_parse(1), http_get(1) +.SH THANKS +.PP +Many thanks to contributors, reviewers, testers: +John LoVerso, Jordan Hayes, Chris Torek, Jim Thompson, Barton Schaffer, +Geoff Adams, Dan Kegel, John Hascall, Bennett Todd, KIKUCHI Takahiro, +Catalin Ionescu. +Special thanks to Craig Leres for substantial debugging and development, +and for not complaining about my coding style very much. +.SH AUTHOR +Copyright © 1995,1998,1999,2000 by Jef Poskanzer . +All rights reserved. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. diff --git a/src/thttpd-2.27/thttpd.c b/src/thttpd-2.27/thttpd.c new file mode 100644 index 0000000..3be7546 --- /dev/null +++ b/src/thttpd-2.27/thttpd.c @@ -0,0 +1,2181 @@ +/* thttpd.c - tiny/turbo/throttling HTTP server +** +** Copyright © 1995,1998,1999,2000,2001,2015 by +** Jef Poskanzer . All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + + +#include "config.h" +#include "version.h" + +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_FCNTL_H +#include +#endif +#include +#ifdef HAVE_GRP_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#include + +#include "fdwatch.h" +#include "libhttpd.h" +#include "mmc.h" +#include "timers.h" +#include "match.h" + +#ifndef SHUT_WR +#define SHUT_WR 1 +#endif + +#ifndef HAVE_INT64T +typedef long long int64_t; +#endif + + +static char* argv0; +static int debug; +static unsigned short port; +static char* dir; +static char* data_dir; +static int do_chroot, no_log, no_symlink_check, do_vhost, do_global_passwd; +static char* cgi_pattern; +static int cgi_limit; +static char* url_pattern; +static int no_empty_referrers; +static char* local_pattern; +static char* logfile; +static char* throttlefile; +static char* hostname; +static char* pidfile; +static char* user; +static char* charset; +static char* p3p; +static int max_age; + + +typedef struct { + char* pattern; + long max_limit, min_limit; + long rate; + off_t bytes_since_avg; + int num_sending; + } throttletab; +static throttletab* throttles; +static int numthrottles, maxthrottles; + +#define THROTTLE_NOLIMIT -1 + + +typedef struct { + int conn_state; + int next_free_connect; + httpd_conn* hc; + int tnums[MAXTHROTTLENUMS]; /* throttle indexes */ + int numtnums; + long max_limit, min_limit; + time_t started_at, active_at; + Timer* wakeup_timer; + Timer* linger_timer; + long wouldblock_delay; + off_t bytes; + off_t end_byte_index; + off_t next_byte_index; + } connecttab; +static connecttab* connects; +static int num_connects, max_connects, first_free_connect; +static int httpd_conn_count; + +/* The connection states. */ +#define CNST_FREE 0 +#define CNST_READING 1 +#define CNST_SENDING 2 +#define CNST_PAUSING 3 +#define CNST_LINGERING 4 + + +static httpd_server* hs = (httpd_server*) 0; +int terminate = 0; +time_t start_time, stats_time; +long stats_connections; +off_t stats_bytes; +int stats_simultaneous; + +static volatile int got_hup, got_usr1, watchdog_flag; + + +/* Forwards. */ +static void parse_args( int argc, char** argv ); +static void usage( void ); +static void read_config( char* filename ); +static void value_required( char* name, char* value ); +static void no_value_required( char* name, char* value ); +static char* e_strdup( char* oldstr ); +static void lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P ); +static void read_throttlefile( char* tf ); +static void shut_down( void ); +static int handle_newconnect( struct timeval* tvP, int listen_fd ); +static void handle_read( connecttab* c, struct timeval* tvP ); +static void handle_send( connecttab* c, struct timeval* tvP ); +static void handle_linger( connecttab* c, struct timeval* tvP ); +static int check_throttles( connecttab* c ); +static void clear_throttles( connecttab* c, struct timeval* tvP ); +static void update_throttles( ClientData client_data, struct timeval* nowP ); +static void finish_connection( connecttab* c, struct timeval* tvP ); +static void clear_connection( connecttab* c, struct timeval* tvP ); +static void really_clear_connection( connecttab* c, struct timeval* tvP ); +static void idle( ClientData client_data, struct timeval* nowP ); +static void wakeup_connection( ClientData client_data, struct timeval* nowP ); +static void linger_clear_connection( ClientData client_data, struct timeval* nowP ); +static void occasional( ClientData client_data, struct timeval* nowP ); +#ifdef STATS_TIME +static void show_stats( ClientData client_data, struct timeval* nowP ); +#endif /* STATS_TIME */ +static void logstats( struct timeval* nowP ); +static void thttpd_logstats( long secs ); + + +/* SIGTERM and SIGINT say to exit immediately. */ +static void +handle_term( int sig ) + { + /* Don't need to set up the handler again, since it's a one-shot. */ + + shut_down(); + syslog( LOG_NOTICE, "exiting due to signal %d", sig ); + closelog(); + exit( 1 ); + } + + +/* SIGCHLD - a chile process exitted, so we need to reap the zombie */ +static void +handle_chld( int sig ) + { + const int oerrno = errno; + pid_t pid; + int status; + +#ifndef HAVE_SIGSET + /* Set up handler again. */ + (void) signal( SIGCHLD, handle_chld ); +#endif /* ! HAVE_SIGSET */ + + /* Reap defunct children until there aren't any more. */ + for (;;) + { +#ifdef HAVE_WAITPID + pid = waitpid( (pid_t) -1, &status, WNOHANG ); +#else /* HAVE_WAITPID */ + pid = wait3( &status, WNOHANG, (struct rusage*) 0 ); +#endif /* HAVE_WAITPID */ + if ( (int) pid == 0 ) /* none left */ + break; + if ( (int) pid < 0 ) + { + if ( errno == EINTR || errno == EAGAIN ) + continue; + /* ECHILD shouldn't happen with the WNOHANG option, + ** but with some kernels it does anyway. Ignore it. + */ + if ( errno != ECHILD ) + syslog( LOG_ERR, "child wait - %m" ); + break; + } + /* Decrement the CGI count. Note that this is not accurate, since + ** each CGI can involve two or even three child processes. + ** Decrementing for each child means that when there is heavy CGI + ** activity, the count will be lower than it should be, and therefore + ** more CGIs will be allowed than should be. + */ + if ( hs != (httpd_server*) 0 ) + { + --hs->cgi_count; + if ( hs->cgi_count < 0 ) + hs->cgi_count = 0; + } + } + + /* Restore previous errno. */ + errno = oerrno; + } + + +/* SIGHUP says to re-open the log file. */ +static void +handle_hup( int sig ) + { + const int oerrno = errno; + +#ifndef HAVE_SIGSET + /* Set up handler again. */ + (void) signal( SIGHUP, handle_hup ); +#endif /* ! HAVE_SIGSET */ + + /* Just set a flag that we got the signal. */ + got_hup = 1; + + /* Restore previous errno. */ + errno = oerrno; + } + + +/* SIGUSR1 says to exit as soon as all current connections are done. */ +static void +handle_usr1( int sig ) + { + /* Don't need to set up the handler again, since it's a one-shot. */ + + if ( num_connects == 0 ) + { + /* If there are no active connections we want to exit immediately + ** here. Not only is it faster, but without any connections the + ** main loop won't wake up until the next new connection. + */ + shut_down(); + syslog( LOG_NOTICE, "exiting" ); + closelog(); + exit( 0 ); + } + + /* Otherwise, just set a flag that we got the signal. */ + got_usr1 = 1; + + /* Don't need to restore old errno, since we didn't do any syscalls. */ + } + + +/* SIGUSR2 says to generate the stats syslogs immediately. */ +static void +handle_usr2( int sig ) + { + const int oerrno = errno; + +#ifndef HAVE_SIGSET + /* Set up handler again. */ + (void) signal( SIGUSR2, handle_usr2 ); +#endif /* ! HAVE_SIGSET */ + + logstats( (struct timeval*) 0 ); + + /* Restore previous errno. */ + errno = oerrno; + } + + +/* SIGALRM is used as a watchdog. */ +static void +handle_alrm( int sig ) + { + const int oerrno = errno; + + /* If nothing has been happening */ + if ( ! watchdog_flag ) + { + /* Try changing dirs to someplace we can write. */ + (void) chdir( "/tmp" ); + /* Dump core. */ + abort(); + } + watchdog_flag = 0; + +#ifndef HAVE_SIGSET + /* Set up handler again. */ + (void) signal( SIGALRM, handle_alrm ); +#endif /* ! HAVE_SIGSET */ + /* Set up alarm again. */ + (void) alarm( OCCASIONAL_TIME * 3 ); + + /* Restore previous errno. */ + errno = oerrno; + } + + +static void +re_open_logfile( void ) + { + FILE* logfp; + + if ( no_log || hs == (httpd_server*) 0 ) + return; + + /* Re-open the log file. */ + if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 ) + { + syslog( LOG_NOTICE, "re-opening logfile" ); + logfp = fopen( logfile, "a" ); + if ( logfp == (FILE*) 0 ) + { + syslog( LOG_CRIT, "re-opening %.80s - %m", logfile ); + return; + } + (void) fcntl( fileno( logfp ), F_SETFD, 1 ); + httpd_set_logfp( hs, logfp ); + } + } + + +int +main( int argc, char** argv ) + { + char* cp; + struct passwd* pwd; + uid_t uid = 32767; + gid_t gid = 32767; + char cwd[MAXPATHLEN+1]; + FILE* logfp; + int num_ready; + int cnum; + connecttab* c; + httpd_conn* hc; + httpd_sockaddr sa4; + httpd_sockaddr sa6; + int gotv4, gotv6; + struct timeval tv; + + argv0 = argv[0]; + + cp = strrchr( argv0, '/' ); + if ( cp != (char*) 0 ) + ++cp; + else + cp = argv0; + openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY ); + + /* Handle command-line arguments. */ + parse_args( argc, argv ); + + /* Read zone info now, in case we chroot(). */ + tzset(); + + /* Look up hostname now, in case we chroot(). */ + lookup_hostname( &sa4, sizeof(sa4), &gotv4, &sa6, sizeof(sa6), &gotv6 ); + if ( ! ( gotv4 || gotv6 ) ) + { + syslog( LOG_ERR, "can't find any valid address" ); + (void) fprintf( stderr, "%s: can't find any valid address\n", argv0 ); + exit( 1 ); + } + + /* Throttle file. */ + numthrottles = 0; + maxthrottles = 0; + throttles = (throttletab*) 0; + if ( throttlefile != (char*) 0 ) + read_throttlefile( throttlefile ); + + /* If we're root and we're going to become another user, get the uid/gid + ** now. + */ + if ( getuid() == 0 ) + { + pwd = getpwnam( user ); + if ( pwd == (struct passwd*) 0 ) + { + syslog( LOG_CRIT, "unknown user - '%.80s'", user ); + (void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user ); + exit( 1 ); + } + uid = pwd->pw_uid; + gid = pwd->pw_gid; + } + + /* Log file. */ + if ( logfile != (char*) 0 ) + { + if ( strcmp( logfile, "/dev/null" ) == 0 ) + { + no_log = 1; + logfp = (FILE*) 0; + } + else if ( strcmp( logfile, "-" ) == 0 ) + logfp = stdout; + else + { + logfp = fopen( logfile, "a" ); + if ( logfp == (FILE*) 0 ) + { + syslog( LOG_CRIT, "%.80s - %m", logfile ); + perror( logfile ); + exit( 1 ); + } + if ( logfile[0] != '/' ) + { + syslog( LOG_WARNING, "logfile is not an absolute path, you may not be able to re-open it" ); + (void) fprintf( stderr, "%s: logfile is not an absolute path, you may not be able to re-open it\n", argv0 ); + } + (void) fcntl( fileno( logfp ), F_SETFD, 1 ); + if ( getuid() == 0 ) + { + /* If we are root then we chown the log file to the user we'll + ** be switching to. + */ + if ( fchown( fileno( logfp ), uid, gid ) < 0 ) + { + syslog( LOG_WARNING, "fchown logfile - %m" ); + perror( "fchown logfile" ); + } + } + } + } + else + logfp = (FILE*) 0; + + /* Switch directories if requested. */ + if ( dir != (char*) 0 ) + { + if ( chdir( dir ) < 0 ) + { + syslog( LOG_CRIT, "chdir - %m" ); + perror( "chdir" ); + exit( 1 ); + } + } +#ifdef USE_USER_DIR + else if ( getuid() == 0 ) + { + /* No explicit directory was specified, we're root, and the + ** USE_USER_DIR option is set - switch to the specified user's + ** home dir. + */ + if ( chdir( pwd->pw_dir ) < 0 ) + { + syslog( LOG_CRIT, "chdir - %m" ); + perror( "chdir" ); + exit( 1 ); + } + } +#endif /* USE_USER_DIR */ + + /* Get current directory. */ + (void) getcwd( cwd, sizeof(cwd) - 1 ); + if ( cwd[strlen( cwd ) - 1] != '/' ) + (void) strcat( cwd, "/" ); + + if ( ! debug ) + { + /* We're not going to use stdin stdout or stderr from here on, so close + ** them to save file descriptors. + */ + (void) fclose( stdin ); + if ( logfp != stdout ) + (void) fclose( stdout ); + (void) fclose( stderr ); + + /* Daemonize - make ourselves a subprocess. */ +#ifdef HAVE_DAEMON + if ( daemon( 1, 1 ) < 0 ) + { + syslog( LOG_CRIT, "daemon - %m" ); + exit( 1 ); + } +#else /* HAVE_DAEMON */ + switch ( fork() ) + { + case 0: + break; + case -1: + syslog( LOG_CRIT, "fork - %m" ); + exit( 1 ); + default: + exit( 0 ); + } +#ifdef HAVE_SETSID + (void) setsid(); +#endif /* HAVE_SETSID */ +#endif /* HAVE_DAEMON */ + } + else + { + /* Even if we don't daemonize, we still want to disown our parent + ** process. + */ +#ifdef HAVE_SETSID + (void) setsid(); +#endif /* HAVE_SETSID */ + } + + if ( pidfile != (char*) 0 ) + { + /* Write the PID file. */ + FILE* pidfp = fopen( pidfile, "w" ); + if ( pidfp == (FILE*) 0 ) + { + syslog( LOG_CRIT, "%.80s - %m", pidfile ); + exit( 1 ); + } + (void) fprintf( pidfp, "%d\n", (int) getpid() ); + (void) fclose( pidfp ); + } + + /* Initialize the fdwatch package. Have to do this before chroot, + ** if /dev/poll is used. + */ + max_connects = fdwatch_get_nfiles(); + if ( max_connects < 0 ) + { + syslog( LOG_CRIT, "fdwatch initialization failure" ); + exit( 1 ); + } + max_connects -= SPARE_FDS; + + /* Chroot if requested. */ + if ( do_chroot ) + { + if ( chroot( cwd ) < 0 ) + { + syslog( LOG_CRIT, "chroot - %m" ); + perror( "chroot" ); + exit( 1 ); + } + /* If we're logging and the logfile's pathname begins with the + ** chroot tree's pathname, then elide the chroot pathname so + ** that the logfile pathname still works from inside the chroot + ** tree. + */ + if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 ) + { + if ( strncmp( logfile, cwd, strlen( cwd ) ) == 0 ) + { + (void) ol_strcpy( logfile, &logfile[strlen( cwd ) - 1] ); + /* (We already guaranteed that cwd ends with a slash, so leaving + ** that slash in logfile makes it an absolute pathname within + ** the chroot tree.) + */ + } + else + { + syslog( LOG_WARNING, "logfile is not within the chroot tree, you will not be able to re-open it" ); + (void) fprintf( stderr, "%s: logfile is not within the chroot tree, you will not be able to re-open it\n", argv0 ); + } + } + (void) strcpy( cwd, "/" ); + /* Always chdir to / after a chroot. */ + if ( chdir( cwd ) < 0 ) + { + syslog( LOG_CRIT, "chroot chdir - %m" ); + perror( "chroot chdir" ); + exit( 1 ); + } + } + + /* Switch directories again if requested. */ + if ( data_dir != (char*) 0 ) + { + if ( chdir( data_dir ) < 0 ) + { + syslog( LOG_CRIT, "data_dir chdir - %m" ); + perror( "data_dir chdir" ); + exit( 1 ); + } + } + + /* Set up to catch signals. */ +#ifdef HAVE_SIGSET + (void) sigset( SIGTERM, handle_term ); + (void) sigset( SIGINT, handle_term ); + (void) sigset( SIGCHLD, handle_chld ); + (void) sigset( SIGPIPE, SIG_IGN ); /* get EPIPE instead */ + (void) sigset( SIGHUP, handle_hup ); + (void) sigset( SIGUSR1, handle_usr1 ); + (void) sigset( SIGUSR2, handle_usr2 ); + (void) sigset( SIGALRM, handle_alrm ); +#else /* HAVE_SIGSET */ + (void) signal( SIGTERM, handle_term ); + (void) signal( SIGINT, handle_term ); + (void) signal( SIGCHLD, handle_chld ); + (void) signal( SIGPIPE, SIG_IGN ); /* get EPIPE instead */ + (void) signal( SIGHUP, handle_hup ); + (void) signal( SIGUSR1, handle_usr1 ); + (void) signal( SIGUSR2, handle_usr2 ); + (void) signal( SIGALRM, handle_alrm ); +#endif /* HAVE_SIGSET */ + got_hup = 0; + got_usr1 = 0; + watchdog_flag = 0; + (void) alarm( OCCASIONAL_TIME * 3 ); + + /* Initialize the timer package. */ + tmr_init(); + + /* Initialize the HTTP layer. Got to do this before giving up root, + ** so that we can bind to a privileged port. + */ + hs = httpd_initialize( + hostname, + gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0, + port, cgi_pattern, cgi_limit, charset, p3p, max_age, cwd, no_log, logfp, + no_symlink_check, do_vhost, do_global_passwd, url_pattern, + local_pattern, no_empty_referrers ); + if ( hs == (httpd_server*) 0 ) + exit( 1 ); + + /* Set up the occasional timer. */ + if ( tmr_create( (struct timeval*) 0, occasional, JunkClientData, OCCASIONAL_TIME * 1000L, 1 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(occasional) failed" ); + exit( 1 ); + } + /* Set up the idle timer. */ + if ( tmr_create( (struct timeval*) 0, idle, JunkClientData, 5 * 1000L, 1 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(idle) failed" ); + exit( 1 ); + } + if ( numthrottles > 0 ) + { + /* Set up the throttles timer. */ + if ( tmr_create( (struct timeval*) 0, update_throttles, JunkClientData, THROTTLE_TIME * 1000L, 1 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(update_throttles) failed" ); + exit( 1 ); + } + } +#ifdef STATS_TIME + /* Set up the stats timer. */ + if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(show_stats) failed" ); + exit( 1 ); + } +#endif /* STATS_TIME */ + start_time = stats_time = time( (time_t*) 0 ); + stats_connections = 0; + stats_bytes = 0; + stats_simultaneous = 0; + + /* If we're root, try to become someone else. */ + if ( getuid() == 0 ) + { + /* Set aux groups to null. */ + if ( setgroups( 0, (const gid_t*) 0 ) < 0 ) + { + syslog( LOG_CRIT, "setgroups - %m" ); + exit( 1 ); + } + /* Set primary group. */ + if ( setgid( gid ) < 0 ) + { + syslog( LOG_CRIT, "setgid - %m" ); + exit( 1 ); + } + /* Try setting aux groups correctly - not critical if this fails. */ + if ( initgroups( user, gid ) < 0 ) + syslog( LOG_WARNING, "initgroups - %m" ); +#ifdef HAVE_SETLOGIN + /* Set login name. */ + (void) setlogin( user ); +#endif /* HAVE_SETLOGIN */ + /* Set uid. */ + if ( setuid( uid ) < 0 ) + { + syslog( LOG_CRIT, "setuid - %m" ); + exit( 1 ); + } + /* Check for unnecessary security exposure. */ + if ( ! do_chroot ) + syslog( + LOG_WARNING, + "started as root without requesting chroot(), warning only" ); + } + + /* Initialize our connections table. */ + connects = NEW( connecttab, max_connects ); + if ( connects == (connecttab*) 0 ) + { + syslog( LOG_CRIT, "out of memory allocating a connecttab" ); + exit( 1 ); + } + for ( cnum = 0; cnum < max_connects; ++cnum ) + { + connects[cnum].conn_state = CNST_FREE; + connects[cnum].next_free_connect = cnum + 1; + connects[cnum].hc = (httpd_conn*) 0; + } + connects[max_connects - 1].next_free_connect = -1; /* end of link list */ + first_free_connect = 0; + num_connects = 0; + httpd_conn_count = 0; + + if ( hs != (httpd_server*) 0 ) + { + if ( hs->listen4_fd != -1 ) + fdwatch_add_fd( hs->listen4_fd, (void*) 0, FDW_READ ); + if ( hs->listen6_fd != -1 ) + fdwatch_add_fd( hs->listen6_fd, (void*) 0, FDW_READ ); + } + + /* Main loop. */ + (void) gettimeofday( &tv, (struct timezone*) 0 ); + while ( ( ! terminate ) || num_connects > 0 ) + { + /* Do we need to re-open the log file? */ + if ( got_hup ) + { + re_open_logfile(); + got_hup = 0; + } + + /* Do the fd watch. */ + num_ready = fdwatch( tmr_mstimeout( &tv ) ); + if ( num_ready < 0 ) + { + if ( errno == EINTR || errno == EAGAIN ) + continue; /* try again */ + syslog( LOG_ERR, "fdwatch - %m" ); + exit( 1 ); + } + (void) gettimeofday( &tv, (struct timezone*) 0 ); + + if ( num_ready == 0 ) + { + /* No fd's are ready - run the timers. */ + tmr_run( &tv ); + continue; + } + + /* Is it a new connection? */ + if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 && + fdwatch_check_fd( hs->listen6_fd ) ) + { + if ( handle_newconnect( &tv, hs->listen6_fd ) ) + /* Go around the loop and do another fdwatch, rather than + ** dropping through and processing existing connections. + ** New connections always get priority. + */ + continue; + } + if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 && + fdwatch_check_fd( hs->listen4_fd ) ) + { + if ( handle_newconnect( &tv, hs->listen4_fd ) ) + /* Go around the loop and do another fdwatch, rather than + ** dropping through and processing existing connections. + ** New connections always get priority. + */ + continue; + } + + /* Find the connections that need servicing. */ + while ( ( c = (connecttab*) fdwatch_get_next_client_data() ) != (connecttab*) -1 ) + { + if ( c == (connecttab*) 0 ) + continue; + hc = c->hc; + if ( ! fdwatch_check_fd( hc->conn_fd ) ) + /* Something went wrong. */ + clear_connection( c, &tv ); + else + switch ( c->conn_state ) + { + case CNST_READING: handle_read( c, &tv ); break; + case CNST_SENDING: handle_send( c, &tv ); break; + case CNST_LINGERING: handle_linger( c, &tv ); break; + } + } + tmr_run( &tv ); + + if ( got_usr1 && ! terminate ) + { + terminate = 1; + if ( hs != (httpd_server*) 0 ) + { + if ( hs->listen4_fd != -1 ) + fdwatch_del_fd( hs->listen4_fd ); + if ( hs->listen6_fd != -1 ) + fdwatch_del_fd( hs->listen6_fd ); + httpd_unlisten( hs ); + } + } + } + + /* The main loop terminated. */ + shut_down(); + syslog( LOG_NOTICE, "exiting" ); + closelog(); + exit( 0 ); + } + + +static void +parse_args( int argc, char** argv ) + { + int argn; + + debug = 0; + port = DEFAULT_PORT; + dir = (char*) 0; + data_dir = (char*) 0; +#ifdef ALWAYS_CHROOT + do_chroot = 1; +#else /* ALWAYS_CHROOT */ + do_chroot = 0; +#endif /* ALWAYS_CHROOT */ + no_log = 0; + no_symlink_check = do_chroot; +#ifdef ALWAYS_VHOST + do_vhost = 1; +#else /* ALWAYS_VHOST */ + do_vhost = 0; +#endif /* ALWAYS_VHOST */ +#ifdef ALWAYS_GLOBAL_PASSWD + do_global_passwd = 1; +#else /* ALWAYS_GLOBAL_PASSWD */ + do_global_passwd = 0; +#endif /* ALWAYS_GLOBAL_PASSWD */ +#ifdef CGI_PATTERN + cgi_pattern = CGI_PATTERN; +#else /* CGI_PATTERN */ + cgi_pattern = (char*) 0; +#endif /* CGI_PATTERN */ +#ifdef CGI_LIMIT + cgi_limit = CGI_LIMIT; +#else /* CGI_LIMIT */ + cgi_limit = 0; +#endif /* CGI_LIMIT */ + url_pattern = (char*) 0; + no_empty_referrers = 0; + local_pattern = (char*) 0; + throttlefile = (char*) 0; + hostname = (char*) 0; + logfile = (char*) 0; + pidfile = (char*) 0; + user = DEFAULT_USER; + charset = DEFAULT_CHARSET; + p3p = ""; + max_age = -1; + argn = 1; + while ( argn < argc && argv[argn][0] == '-' ) + { + if ( strcmp( argv[argn], "-V" ) == 0 ) + { + (void) printf( "%s\n", SERVER_SOFTWARE ); + exit( 0 ); + } + else if ( strcmp( argv[argn], "-C" ) == 0 && argn + 1 < argc ) + { + ++argn; + read_config( argv[argn] ); + } + else if ( strcmp( argv[argn], "-p" ) == 0 && argn + 1 < argc ) + { + ++argn; + port = (unsigned short) atoi( argv[argn] ); + } + else if ( strcmp( argv[argn], "-d" ) == 0 && argn + 1 < argc ) + { + ++argn; + dir = argv[argn]; + } + else if ( strcmp( argv[argn], "-r" ) == 0 ) + { + do_chroot = 1; + no_symlink_check = 1; + } + else if ( strcmp( argv[argn], "-nor" ) == 0 ) + { + do_chroot = 0; + no_symlink_check = 0; + } + else if ( strcmp( argv[argn], "-dd" ) == 0 && argn + 1 < argc ) + { + ++argn; + data_dir = argv[argn]; + } + else if ( strcmp( argv[argn], "-s" ) == 0 ) + no_symlink_check = 0; + else if ( strcmp( argv[argn], "-nos" ) == 0 ) + no_symlink_check = 1; + else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc ) + { + ++argn; + user = argv[argn]; + } + else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc ) + { + ++argn; + cgi_pattern = argv[argn]; + } + else if ( strcmp( argv[argn], "-t" ) == 0 && argn + 1 < argc ) + { + ++argn; + throttlefile = argv[argn]; + } + else if ( strcmp( argv[argn], "-h" ) == 0 && argn + 1 < argc ) + { + ++argn; + hostname = argv[argn]; + } + else if ( strcmp( argv[argn], "-l" ) == 0 && argn + 1 < argc ) + { + ++argn; + logfile = argv[argn]; + } + else if ( strcmp( argv[argn], "-v" ) == 0 ) + do_vhost = 1; + else if ( strcmp( argv[argn], "-nov" ) == 0 ) + do_vhost = 0; + else if ( strcmp( argv[argn], "-g" ) == 0 ) + do_global_passwd = 1; + else if ( strcmp( argv[argn], "-nog" ) == 0 ) + do_global_passwd = 0; + else if ( strcmp( argv[argn], "-i" ) == 0 && argn + 1 < argc ) + { + ++argn; + pidfile = argv[argn]; + } + else if ( strcmp( argv[argn], "-T" ) == 0 && argn + 1 < argc ) + { + ++argn; + charset = argv[argn]; + } + else if ( strcmp( argv[argn], "-P" ) == 0 && argn + 1 < argc ) + { + ++argn; + p3p = argv[argn]; + } + else if ( strcmp( argv[argn], "-M" ) == 0 && argn + 1 < argc ) + { + ++argn; + max_age = atoi( argv[argn] ); + } + else if ( strcmp( argv[argn], "-D" ) == 0 ) + debug = 1; + else + usage(); + ++argn; + } + if ( argn != argc ) + usage(); + } + + +static void +usage( void ) + { + (void) fprintf( stderr, +"usage: %s [-C configfile] [-p port] [-d dir] [-r|-nor] [-dd data_dir] [-s|-nos] [-v|-nov] [-g|-nog] [-u user] [-c cgipat] [-t throttles] [-h host] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage] [-V] [-D]\n", + argv0 ); + exit( 1 ); + } + + +static void +read_config( char* filename ) + { + FILE* fp; + char line[10000]; + char* cp; + char* cp2; + char* name; + char* value; + + fp = fopen( filename, "r" ); + if ( fp == (FILE*) 0 ) + { + perror( filename ); + exit( 1 ); + } + + while ( fgets( line, sizeof(line), fp ) != (char*) 0 ) + { + /* Trim comments. */ + if ( ( cp = strchr( line, '#' ) ) != (char*) 0 ) + *cp = '\0'; + + /* Skip leading whitespace. */ + cp = line; + cp += strspn( cp, " \t\n\r" ); + + /* Split line into words. */ + while ( *cp != '\0' ) + { + /* Find next whitespace. */ + cp2 = cp + strcspn( cp, " \t\n\r" ); + /* Insert EOS and advance next-word pointer. */ + while ( *cp2 == ' ' || *cp2 == '\t' || *cp2 == '\n' || *cp2 == '\r' ) + *cp2++ = '\0'; + /* Split into name and value. */ + name = cp; + value = strchr( name, '=' ); + if ( value != (char*) 0 ) + *value++ = '\0'; + /* Interpret. */ + if ( strcasecmp( name, "debug" ) == 0 ) + { + no_value_required( name, value ); + debug = 1; + } + else if ( strcasecmp( name, "port" ) == 0 ) + { + value_required( name, value ); + port = (unsigned short) atoi( value ); + } + else if ( strcasecmp( name, "dir" ) == 0 ) + { + value_required( name, value ); + dir = e_strdup( value ); + } + else if ( strcasecmp( name, "chroot" ) == 0 ) + { + no_value_required( name, value ); + do_chroot = 1; + no_symlink_check = 1; + } + else if ( strcasecmp( name, "nochroot" ) == 0 ) + { + no_value_required( name, value ); + do_chroot = 0; + no_symlink_check = 0; + } + else if ( strcasecmp( name, "data_dir" ) == 0 ) + { + value_required( name, value ); + data_dir = e_strdup( value ); + } + else if ( strcasecmp( name, "nosymlinkcheck" ) == 0 ) + { + no_value_required( name, value ); + no_symlink_check = 1; + } + else if ( strcasecmp( name, "symlinkcheck" ) == 0 ) + { + no_value_required( name, value ); + no_symlink_check = 0; + } + else if ( strcasecmp( name, "user" ) == 0 ) + { + value_required( name, value ); + user = e_strdup( value ); + } + else if ( strcasecmp( name, "cgipat" ) == 0 ) + { + value_required( name, value ); + cgi_pattern = e_strdup( value ); + } + else if ( strcasecmp( name, "cgilimit" ) == 0 ) + { + value_required( name, value ); + cgi_limit = atoi( value ); + } + else if ( strcasecmp( name, "urlpat" ) == 0 ) + { + value_required( name, value ); + url_pattern = e_strdup( value ); + } + else if ( strcasecmp( name, "noemptyreferers" ) == 0 || + strcasecmp( name, "noemptyreferrers" ) == 0 ) + { + no_value_required( name, value ); + no_empty_referrers = 1; + } + else if ( strcasecmp( name, "localpat" ) == 0 ) + { + value_required( name, value ); + local_pattern = e_strdup( value ); + } + else if ( strcasecmp( name, "throttles" ) == 0 ) + { + value_required( name, value ); + throttlefile = e_strdup( value ); + } + else if ( strcasecmp( name, "host" ) == 0 ) + { + value_required( name, value ); + hostname = e_strdup( value ); + } + else if ( strcasecmp( name, "logfile" ) == 0 ) + { + value_required( name, value ); + logfile = e_strdup( value ); + } + else if ( strcasecmp( name, "vhost" ) == 0 ) + { + no_value_required( name, value ); + do_vhost = 1; + } + else if ( strcasecmp( name, "novhost" ) == 0 ) + { + no_value_required( name, value ); + do_vhost = 0; + } + else if ( strcasecmp( name, "globalpasswd" ) == 0 ) + { + no_value_required( name, value ); + do_global_passwd = 1; + } + else if ( strcasecmp( name, "noglobalpasswd" ) == 0 ) + { + no_value_required( name, value ); + do_global_passwd = 0; + } + else if ( strcasecmp( name, "pidfile" ) == 0 ) + { + value_required( name, value ); + pidfile = e_strdup( value ); + } + else if ( strcasecmp( name, "charset" ) == 0 ) + { + value_required( name, value ); + charset = e_strdup( value ); + } + else if ( strcasecmp( name, "p3p" ) == 0 ) + { + value_required( name, value ); + p3p = e_strdup( value ); + } + else if ( strcasecmp( name, "max_age" ) == 0 ) + { + value_required( name, value ); + max_age = atoi( value ); + } + else + { + (void) fprintf( + stderr, "%s: unknown config option '%s'\n", argv0, name ); + exit( 1 ); + } + + /* Advance to next word. */ + cp = cp2; + cp += strspn( cp, " \t\n\r" ); + } + } + + (void) fclose( fp ); + } + + +static void +value_required( char* name, char* value ) + { + if ( value == (char*) 0 ) + { + (void) fprintf( + stderr, "%s: value required for %s option\n", argv0, name ); + exit( 1 ); + } + } + + +static void +no_value_required( char* name, char* value ) + { + if ( value != (char*) 0 ) + { + (void) fprintf( + stderr, "%s: no value required for %s option\n", + argv0, name ); + exit( 1 ); + } + } + + +static char* +e_strdup( char* oldstr ) + { + char* newstr; + + newstr = strdup( oldstr ); + if ( newstr == (char*) 0 ) + { + syslog( LOG_CRIT, "out of memory copying a string" ); + (void) fprintf( stderr, "%s: out of memory copying a string\n", argv0 ); + exit( 1 ); + } + return newstr; + } + + +static void +lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P ) + { +#ifdef USE_IPV6 + + struct addrinfo hints; + char portstr[10]; + int gaierr; + struct addrinfo* ai; + struct addrinfo* ai2; + struct addrinfo* aiv6; + struct addrinfo* aiv4; + + (void) memset( &hints, 0, sizeof(hints) ); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + (void) snprintf( portstr, sizeof(portstr), "%d", (int) port ); + if ( (gaierr = getaddrinfo( hostname, portstr, &hints, &ai )) != 0 ) + { + syslog( + LOG_CRIT, "getaddrinfo %.80s - %.80s", + hostname, gai_strerror( gaierr ) ); + (void) fprintf( + stderr, "%s: getaddrinfo %s - %s\n", + argv0, hostname, gai_strerror( gaierr ) ); + exit( 1 ); + } + + /* Find the first IPv6 and IPv4 entries. */ + aiv6 = (struct addrinfo*) 0; + aiv4 = (struct addrinfo*) 0; + for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next ) + { + switch ( ai2->ai_family ) + { + case AF_INET6: + if ( aiv6 == (struct addrinfo*) 0 ) + aiv6 = ai2; + break; + case AF_INET: + if ( aiv4 == (struct addrinfo*) 0 ) + aiv4 = ai2; + break; + } + } + + if ( aiv6 == (struct addrinfo*) 0 ) + *gotv6P = 0; + else + { + if ( sa6_len < aiv6->ai_addrlen ) + { + syslog( + LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)", + hostname, (unsigned long) sa6_len, + (unsigned long) aiv6->ai_addrlen ); + exit( 1 ); + } + (void) memset( sa6P, 0, sa6_len ); + (void) memmove( sa6P, aiv6->ai_addr, aiv6->ai_addrlen ); + *gotv6P = 1; + } + + if ( aiv4 == (struct addrinfo*) 0 ) + *gotv4P = 0; + else + { + if ( sa4_len < aiv4->ai_addrlen ) + { + syslog( + LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)", + hostname, (unsigned long) sa4_len, + (unsigned long) aiv4->ai_addrlen ); + exit( 1 ); + } + (void) memset( sa4P, 0, sa4_len ); + (void) memmove( sa4P, aiv4->ai_addr, aiv4->ai_addrlen ); + *gotv4P = 1; + } + + freeaddrinfo( ai ); + +#else /* USE_IPV6 */ + + struct hostent* he; + + *gotv6P = 0; + + (void) memset( sa4P, 0, sa4_len ); + sa4P->sa.sa_family = AF_INET; + if ( hostname == (char*) 0 ) + sa4P->sa_in.sin_addr.s_addr = htonl( INADDR_ANY ); + else + { + sa4P->sa_in.sin_addr.s_addr = inet_addr( hostname ); + if ( (int) sa4P->sa_in.sin_addr.s_addr == -1 ) + { + he = gethostbyname( hostname ); + if ( he == (struct hostent*) 0 ) + { +#ifdef HAVE_HSTRERROR + syslog( + LOG_CRIT, "gethostbyname %.80s - %.80s", + hostname, hstrerror( h_errno ) ); + (void) fprintf( + stderr, "%s: gethostbyname %s - %s\n", + argv0, hostname, hstrerror( h_errno ) ); +#else /* HAVE_HSTRERROR */ + syslog( LOG_CRIT, "gethostbyname %.80s failed", hostname ); + (void) fprintf( + stderr, "%s: gethostbyname %s failed\n", argv0, hostname ); +#endif /* HAVE_HSTRERROR */ + exit( 1 ); + } + if ( he->h_addrtype != AF_INET ) + { + syslog( LOG_CRIT, "%.80s - non-IP network address", hostname ); + (void) fprintf( + stderr, "%s: %s - non-IP network address\n", + argv0, hostname ); + exit( 1 ); + } + (void) memmove( + &sa4P->sa_in.sin_addr.s_addr, he->h_addr, he->h_length ); + } + } + sa4P->sa_in.sin_port = htons( port ); + *gotv4P = 1; + +#endif /* USE_IPV6 */ + } + + +static void +read_throttlefile( char* tf ) + { + FILE* fp; + char buf[5000]; + char* cp; + int len; + char pattern[5000]; + long max_limit, min_limit; + struct timeval tv; + + fp = fopen( tf, "r" ); + if ( fp == (FILE*) 0 ) + { + syslog( LOG_CRIT, "%.80s - %m", tf ); + perror( tf ); + exit( 1 ); + } + + (void) gettimeofday( &tv, (struct timezone*) 0 ); + + while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 ) + { + /* Nuke comments. */ + cp = strchr( buf, '#' ); + if ( cp != (char*) 0 ) + *cp = '\0'; + + /* Nuke trailing whitespace. */ + len = strlen( buf ); + while ( len > 0 && + ( buf[len-1] == ' ' || buf[len-1] == '\t' || + buf[len-1] == '\n' || buf[len-1] == '\r' ) ) + buf[--len] = '\0'; + + /* Ignore empty lines. */ + if ( len == 0 ) + continue; + + /* Parse line. */ + if ( sscanf( buf, " %4900[^ \t] %ld-%ld", pattern, &min_limit, &max_limit ) == 3 ) + {} + else if ( sscanf( buf, " %4900[^ \t] %ld", pattern, &max_limit ) == 2 ) + min_limit = 0; + else + { + syslog( LOG_CRIT, + "unparsable line in %.80s - %.80s", tf, buf ); + (void) fprintf( stderr, + "%s: unparsable line in %.80s - %.80s\n", + argv0, tf, buf ); + continue; + } + + /* Nuke any leading slashes in pattern. */ + if ( pattern[0] == '/' ) + (void) ol_strcpy( pattern, &pattern[1] ); + while ( ( cp = strstr( pattern, "|/" ) ) != (char*) 0 ) + (void) ol_strcpy( cp + 1, cp + 2 ); + + /* Check for room in throttles. */ + if ( numthrottles >= maxthrottles ) + { + if ( maxthrottles == 0 ) + { + maxthrottles = 100; /* arbitrary */ + throttles = NEW( throttletab, maxthrottles ); + } + else + { + maxthrottles *= 2; + throttles = RENEW( throttles, throttletab, maxthrottles ); + } + if ( throttles == (throttletab*) 0 ) + { + syslog( LOG_CRIT, "out of memory allocating a throttletab" ); + (void) fprintf( + stderr, "%s: out of memory allocating a throttletab\n", + argv0 ); + exit( 1 ); + } + } + + /* Add to table. */ + throttles[numthrottles].pattern = e_strdup( pattern ); + throttles[numthrottles].max_limit = max_limit; + throttles[numthrottles].min_limit = min_limit; + throttles[numthrottles].rate = 0; + throttles[numthrottles].bytes_since_avg = 0; + throttles[numthrottles].num_sending = 0; + + ++numthrottles; + } + (void) fclose( fp ); + } + + +static void +shut_down( void ) + { + int cnum; + struct timeval tv; + + (void) gettimeofday( &tv, (struct timezone*) 0 ); + logstats( &tv ); + for ( cnum = 0; cnum < max_connects; ++cnum ) + { + if ( connects[cnum].conn_state != CNST_FREE ) + httpd_close_conn( connects[cnum].hc, &tv ); + if ( connects[cnum].hc != (httpd_conn*) 0 ) + { + httpd_destroy_conn( connects[cnum].hc ); + free( (void*) connects[cnum].hc ); + --httpd_conn_count; + connects[cnum].hc = (httpd_conn*) 0; + } + } + if ( hs != (httpd_server*) 0 ) + { + httpd_server* ths = hs; + hs = (httpd_server*) 0; + if ( ths->listen4_fd != -1 ) + fdwatch_del_fd( ths->listen4_fd ); + if ( ths->listen6_fd != -1 ) + fdwatch_del_fd( ths->listen6_fd ); + httpd_terminate( ths ); + } + mmc_term(); + tmr_term(); + free( (void*) connects ); + if ( throttles != (throttletab*) 0 ) + free( (void*) throttles ); + } + + +static int +handle_newconnect( struct timeval* tvP, int listen_fd ) + { + connecttab* c; + ClientData client_data; + + /* This loops until the accept() fails, trying to start new + ** connections as fast as possible so we don't overrun the + ** listen queue. + */ + for (;;) + { + /* Is there room in the connection table? */ + if ( num_connects >= max_connects ) + { + /* Out of connection slots. Run the timers, then the + ** existing connections, and maybe we'll free up a slot + ** by the time we get back here. + */ + syslog( LOG_WARNING, "too many connections!" ); + tmr_run( tvP ); + return 0; + } + /* Get the first free connection entry off the free list. */ + if ( first_free_connect == -1 || connects[first_free_connect].conn_state != CNST_FREE ) + { + syslog( LOG_CRIT, "the connects free list is messed up" ); + exit( 1 ); + } + c = &connects[first_free_connect]; + /* Make the httpd_conn if necessary. */ + if ( c->hc == (httpd_conn*) 0 ) + { + c->hc = NEW( httpd_conn, 1 ); + if ( c->hc == (httpd_conn*) 0 ) + { + syslog( LOG_CRIT, "out of memory allocating an httpd_conn" ); + exit( 1 ); + } + c->hc->initialized = 0; + ++httpd_conn_count; + } + + /* Get the connection. */ + switch ( httpd_get_conn( hs, listen_fd, c->hc ) ) + { + /* Some error happened. Run the timers, then the + ** existing connections. Maybe the error will clear. + */ + case GC_FAIL: + tmr_run( tvP ); + return 0; + + /* No more connections to accept for now. */ + case GC_NO_MORE: + return 1; + } + c->conn_state = CNST_READING; + /* Pop it off the free list. */ + first_free_connect = c->next_free_connect; + c->next_free_connect = -1; + ++num_connects; + client_data.p = c; + c->active_at = tvP->tv_sec; + c->wakeup_timer = (Timer*) 0; + c->linger_timer = (Timer*) 0; + c->next_byte_index = 0; + c->numtnums = 0; + + /* Set the connection file descriptor to no-delay mode. */ + httpd_set_ndelay( c->hc->conn_fd ); + + fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ ); + + ++stats_connections; + if ( num_connects > stats_simultaneous ) + stats_simultaneous = num_connects; + } + } + + +static void +handle_read( connecttab* c, struct timeval* tvP ) + { + int sz; + ClientData client_data; + httpd_conn* hc = c->hc; + + /* Is there room in our buffer to read more bytes? */ + if ( hc->read_idx >= hc->read_size ) + { + if ( hc->read_size > 5000 ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + finish_connection( c, tvP ); + return; + } + httpd_realloc_str( + &hc->read_buf, &hc->read_size, hc->read_size + 1000 ); + } + + /* Read some more bytes. */ + sz = read( + hc->conn_fd, &(hc->read_buf[hc->read_idx]), + hc->read_size - hc->read_idx ); + if ( sz == 0 ) + { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + finish_connection( c, tvP ); + return; + } + if ( sz < 0 ) + { + /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance + ** you would think that connections returned by fdwatch as readable + ** should never give an EWOULDBLOCK; however, this apparently can + ** happen if a packet gets garbled. + */ + if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) + return; + httpd_send_err( + hc, 400, httpd_err400title, "", httpd_err400form, "" ); + finish_connection( c, tvP ); + return; + } + hc->read_idx += sz; + c->active_at = tvP->tv_sec; + + /* Do we have a complete request yet? */ + switch ( httpd_got_request( hc ) ) + { + case GR_NO_REQUEST: + return; + case GR_BAD_REQUEST: + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + finish_connection( c, tvP ); + return; + } + + /* Yes. Try parsing and resolving it. */ + if ( httpd_parse_request( hc ) < 0 ) + { + finish_connection( c, tvP ); + return; + } + + /* Check the throttle table */ + if ( ! check_throttles( c ) ) + { + httpd_send_err( + hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl ); + finish_connection( c, tvP ); + return; + } + + /* Start the connection going. */ + if ( httpd_start_request( hc, tvP ) < 0 ) + { + /* Something went wrong. Close down the connection. */ + finish_connection( c, tvP ); + return; + } + + /* Fill in end_byte_index. */ + if ( hc->got_range ) + { + c->next_byte_index = hc->first_byte_index; + c->end_byte_index = hc->last_byte_index + 1; + } + else if ( hc->bytes_to_send < 0 ) + c->end_byte_index = 0; + else + c->end_byte_index = hc->bytes_to_send; + + /* Check if it's already handled. */ + if ( hc->file_address == (char*) 0 ) + { + /* No file address means someone else is handling it. */ + int tind; + for ( tind = 0; tind < c->numtnums; ++tind ) + throttles[c->tnums[tind]].bytes_since_avg += hc->bytes_sent; + c->next_byte_index = hc->bytes_sent; + finish_connection( c, tvP ); + return; + } + if ( c->next_byte_index >= c->end_byte_index ) + { + /* There's nothing to send. */ + finish_connection( c, tvP ); + return; + } + + /* Cool, we have a valid connection and a file to send to it. */ + c->conn_state = CNST_SENDING; + c->started_at = tvP->tv_sec; + c->wouldblock_delay = 0; + client_data.p = c; + + fdwatch_del_fd( hc->conn_fd ); + fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE ); + } + + +static void +handle_send( connecttab* c, struct timeval* tvP ) + { + size_t max_bytes; + int sz, coast; + ClientData client_data; + time_t elapsed; + httpd_conn* hc = c->hc; + int tind; + + if ( c->max_limit == THROTTLE_NOLIMIT ) + max_bytes = 1000000000L; + else + max_bytes = c->max_limit / 4; /* send at most 1/4 seconds worth */ + + /* Do we need to write the headers first? */ + if ( hc->responselen == 0 ) + { + /* No, just write the file. */ + sz = write( + hc->conn_fd, &(hc->file_address[c->next_byte_index]), + MIN( c->end_byte_index - c->next_byte_index, max_bytes ) ); + } + else + { + /* Yes. We'll combine headers and file into a single writev(), + ** hoping that this generates a single packet. + */ + struct iovec iv[2]; + + iv[0].iov_base = hc->response; + iv[0].iov_len = hc->responselen; + iv[1].iov_base = &(hc->file_address[c->next_byte_index]); + iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes ); + sz = writev( hc->conn_fd, iv, 2 ); + } + + if ( sz < 0 && errno == EINTR ) + return; + + if ( sz == 0 || + ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) ) + { + /* This shouldn't happen, but some kernels, e.g. + ** SunOS 4.1.x, are broken and select() says that + ** O_NDELAY sockets are always writable even when + ** they're actually not. + ** + ** Current workaround is to block sending on this + ** socket for a brief adaptively-tuned period. + ** Fortunately we already have all the necessary + ** blocking code, for use with throttling. + */ + c->wouldblock_delay += MIN_WOULDBLOCK_DELAY; + c->conn_state = CNST_PAUSING; + fdwatch_del_fd( hc->conn_fd ); + client_data.p = c; + if ( c->wakeup_timer != (Timer*) 0 ) + syslog( LOG_ERR, "replacing non-null wakeup_timer!" ); + c->wakeup_timer = tmr_create( + tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 ); + if ( c->wakeup_timer == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" ); + exit( 1 ); + } + return; + } + + if ( sz < 0 ) + { + /* Something went wrong, close this connection. + ** + ** If it's just an EPIPE, don't bother logging, that + ** just means the client hung up on us. + ** + ** On some systems, write() occasionally gives an EINVAL. + ** Dunno why, something to do with the socket going + ** bad. Anyway, we don't log those either. + ** + ** And ECONNRESET isn't interesting either. + */ + if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET ) + syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl ); + clear_connection( c, tvP ); + return; + } + + /* Ok, we wrote something. */ + c->active_at = tvP->tv_sec; + /* Was this a headers + file writev()? */ + if ( hc->responselen > 0 ) + { + /* Yes; did we write only part of the headers? */ + if ( sz < hc->responselen ) + { + /* Yes; move the unwritten part to the front of the buffer. */ + int newlen = hc->responselen - sz; + (void) memmove( hc->response, &(hc->response[sz]), newlen ); + hc->responselen = newlen; + sz = 0; + } + else + { + /* Nope, we wrote the full headers, so adjust accordingly. */ + sz -= hc->responselen; + hc->responselen = 0; + } + } + /* And update how much of the file we wrote. */ + c->next_byte_index += sz; + c->hc->bytes_sent += sz; + for ( tind = 0; tind < c->numtnums; ++tind ) + throttles[c->tnums[tind]].bytes_since_avg += sz; + + /* Are we done? */ + if ( c->next_byte_index >= c->end_byte_index ) + { + /* This connection is finished! */ + finish_connection( c, tvP ); + return; + } + + /* Tune the (blockheaded) wouldblock delay. */ + if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY ) + c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY; + + /* If we're throttling, check if we're sending too fast. */ + if ( c->max_limit != THROTTLE_NOLIMIT ) + { + elapsed = tvP->tv_sec - c->started_at; + if ( elapsed == 0 ) + elapsed = 1; /* count at least one second */ + if ( c->hc->bytes_sent / elapsed > c->max_limit ) + { + c->conn_state = CNST_PAUSING; + fdwatch_del_fd( hc->conn_fd ); + /* How long should we wait to get back on schedule? If less + ** than a second (integer math rounding), use 1/2 second. + */ + coast = c->hc->bytes_sent / c->max_limit - elapsed; + client_data.p = c; + if ( c->wakeup_timer != (Timer*) 0 ) + syslog( LOG_ERR, "replacing non-null wakeup_timer!" ); + c->wakeup_timer = tmr_create( + tvP, wakeup_connection, client_data, + coast > 0 ? ( coast * 1000L ) : 500L, 0 ); + if ( c->wakeup_timer == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" ); + exit( 1 ); + } + } + } + /* (No check on min_limit here, that only controls connection startups.) */ + } + + +static void +handle_linger( connecttab* c, struct timeval* tvP ) + { + char buf[4096]; + int r; + + /* In lingering-close mode we just read and ignore bytes. An error + ** or EOF ends things, otherwise we go until a timeout. + */ + r = read( c->hc->conn_fd, buf, sizeof(buf) ); + if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) + return; + if ( r <= 0 ) + really_clear_connection( c, tvP ); + } + + +static int +check_throttles( connecttab* c ) + { + int tnum; + long l; + + c->numtnums = 0; + c->max_limit = c->min_limit = THROTTLE_NOLIMIT; + for ( tnum = 0; tnum < numthrottles && c->numtnums < MAXTHROTTLENUMS; + ++tnum ) + if ( match( throttles[tnum].pattern, c->hc->expnfilename ) ) + { + /* If we're way over the limit, don't even start. */ + if ( throttles[tnum].rate > throttles[tnum].max_limit * 2 ) + return 0; + /* Also don't start if we're under the minimum. */ + if ( throttles[tnum].rate < throttles[tnum].min_limit ) + return 0; + if ( throttles[tnum].num_sending < 0 ) + { + syslog( LOG_ERR, "throttle sending count was negative - shouldn't happen!" ); + throttles[tnum].num_sending = 0; + } + c->tnums[c->numtnums++] = tnum; + ++throttles[tnum].num_sending; + l = throttles[tnum].max_limit / throttles[tnum].num_sending; + if ( c->max_limit == THROTTLE_NOLIMIT ) + c->max_limit = l; + else + c->max_limit = MIN( c->max_limit, l ); + l = throttles[tnum].min_limit; + if ( c->min_limit == THROTTLE_NOLIMIT ) + c->min_limit = l; + else + c->min_limit = MAX( c->min_limit, l ); + } + return 1; + } + + +static void +clear_throttles( connecttab* c, struct timeval* tvP ) + { + int tind; + + for ( tind = 0; tind < c->numtnums; ++tind ) + --throttles[c->tnums[tind]].num_sending; + } + + +static void +update_throttles( ClientData client_data, struct timeval* nowP ) + { + int tnum, tind; + int cnum; + connecttab* c; + long l; + + /* Update the average sending rate for each throttle. This is only used + ** when new connections start up. + */ + for ( tnum = 0; tnum < numthrottles; ++tnum ) + { + throttles[tnum].rate = ( 2 * throttles[tnum].rate + throttles[tnum].bytes_since_avg / THROTTLE_TIME ) / 3; + throttles[tnum].bytes_since_avg = 0; + /* Log a warning message if necessary. */ + if ( throttles[tnum].rate > throttles[tnum].max_limit && throttles[tnum].num_sending != 0 ) + { + if ( throttles[tnum].rate > throttles[tnum].max_limit * 2 ) + syslog( LOG_NOTICE, "throttle #%d '%.80s' rate %ld greatly exceeding limit %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].max_limit, throttles[tnum].num_sending ); + else + syslog( LOG_INFO, "throttle #%d '%.80s' rate %ld exceeding limit %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].max_limit, throttles[tnum].num_sending ); + } + if ( throttles[tnum].rate < throttles[tnum].min_limit && throttles[tnum].num_sending != 0 ) + { + syslog( LOG_NOTICE, "throttle #%d '%.80s' rate %ld lower than minimum %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].min_limit, throttles[tnum].num_sending ); + } + } + + /* Now update the sending rate on all the currently-sending connections, + ** redistributing it evenly. + */ + for ( cnum = 0; cnum < max_connects; ++cnum ) + { + c = &connects[cnum]; + if ( c->conn_state == CNST_SENDING || c->conn_state == CNST_PAUSING ) + { + c->max_limit = THROTTLE_NOLIMIT; + for ( tind = 0; tind < c->numtnums; ++tind ) + { + tnum = c->tnums[tind]; + l = throttles[tnum].max_limit / throttles[tnum].num_sending; + if ( c->max_limit == THROTTLE_NOLIMIT ) + c->max_limit = l; + else + c->max_limit = MIN( c->max_limit, l ); + } + } + } + } + + +static void +finish_connection( connecttab* c, struct timeval* tvP ) + { + /* If we haven't actually sent the buffered response yet, do so now. */ + httpd_write_response( c->hc ); + + /* And clear. */ + clear_connection( c, tvP ); + } + + +static void +clear_connection( connecttab* c, struct timeval* tvP ) + { + ClientData client_data; + + if ( c->wakeup_timer != (Timer*) 0 ) + { + tmr_cancel( c->wakeup_timer ); + c->wakeup_timer = 0; + } + + /* This is our version of Apache's lingering_close() routine, which is + ** their version of the often-broken SO_LINGER socket option. For why + ** this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html + ** What we do is delay the actual closing for a few seconds, while reading + ** any bytes that come over the connection. However, we don't want to do + ** this unless it's necessary, because it ties up a connection slot and + ** file descriptor which means our maximum connection-handling rate + ** is lower. So, elsewhere we set a flag when we detect the few + ** circumstances that make a lingering close necessary. If the flag + ** isn't set we do the real close now. + */ + if ( c->conn_state == CNST_LINGERING ) + { + /* If we were already lingering, shut down for real. */ + tmr_cancel( c->linger_timer ); + c->linger_timer = (Timer*) 0; + c->hc->should_linger = 0; + } + if ( c->hc->should_linger ) + { + if ( c->conn_state != CNST_PAUSING ) + fdwatch_del_fd( c->hc->conn_fd ); + c->conn_state = CNST_LINGERING; + shutdown( c->hc->conn_fd, SHUT_WR ); + fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ ); + client_data.p = c; + if ( c->linger_timer != (Timer*) 0 ) + syslog( LOG_ERR, "replacing non-null linger_timer!" ); + c->linger_timer = tmr_create( + tvP, linger_clear_connection, client_data, LINGER_TIME, 0 ); + if ( c->linger_timer == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" ); + exit( 1 ); + } + } + else + really_clear_connection( c, tvP ); + } + + +static void +really_clear_connection( connecttab* c, struct timeval* tvP ) + { + stats_bytes += c->hc->bytes_sent; + if ( c->conn_state != CNST_PAUSING ) + fdwatch_del_fd( c->hc->conn_fd ); + httpd_close_conn( c->hc, tvP ); + clear_throttles( c, tvP ); + if ( c->linger_timer != (Timer*) 0 ) + { + tmr_cancel( c->linger_timer ); + c->linger_timer = 0; + } + c->conn_state = CNST_FREE; + c->next_free_connect = first_free_connect; + first_free_connect = c - connects; /* division by sizeof is implied */ + --num_connects; + } + + +static void +idle( ClientData client_data, struct timeval* nowP ) + { + int cnum; + connecttab* c; + + for ( cnum = 0; cnum < max_connects; ++cnum ) + { + c = &connects[cnum]; + switch ( c->conn_state ) + { + case CNST_READING: + if ( nowP->tv_sec - c->active_at >= IDLE_READ_TIMELIMIT ) + { + syslog( LOG_INFO, + "%.80s connection timed out reading", + httpd_ntoa( &c->hc->client_addr ) ); + httpd_send_err( + c->hc, 408, httpd_err408title, "", httpd_err408form, "" ); + finish_connection( c, nowP ); + } + break; + case CNST_SENDING: + case CNST_PAUSING: + if ( nowP->tv_sec - c->active_at >= IDLE_SEND_TIMELIMIT ) + { + syslog( LOG_INFO, + "%.80s connection timed out sending", + httpd_ntoa( &c->hc->client_addr ) ); + clear_connection( c, nowP ); + } + break; + } + } + } + + +static void +wakeup_connection( ClientData client_data, struct timeval* nowP ) + { + connecttab* c; + + c = (connecttab*) client_data.p; + c->wakeup_timer = (Timer*) 0; + if ( c->conn_state == CNST_PAUSING ) + { + c->conn_state = CNST_SENDING; + fdwatch_add_fd( c->hc->conn_fd, c, FDW_WRITE ); + } + } + +static void +linger_clear_connection( ClientData client_data, struct timeval* nowP ) + { + connecttab* c; + + c = (connecttab*) client_data.p; + c->linger_timer = (Timer*) 0; + really_clear_connection( c, nowP ); + } + + +static void +occasional( ClientData client_data, struct timeval* nowP ) + { + mmc_cleanup( nowP ); + tmr_cleanup(); + watchdog_flag = 1; /* let the watchdog know that we are alive */ + } + + +#ifdef STATS_TIME +static void +show_stats( ClientData client_data, struct timeval* nowP ) + { + logstats( nowP ); + } +#endif /* STATS_TIME */ + + +/* Generate debugging statistics syslog messages for all packages. */ +static void +logstats( struct timeval* nowP ) + { + struct timeval tv; + time_t now; + long up_secs, stats_secs; + + if ( nowP == (struct timeval*) 0 ) + { + (void) gettimeofday( &tv, (struct timezone*) 0 ); + nowP = &tv; + } + now = nowP->tv_sec; + up_secs = now - start_time; + stats_secs = now - stats_time; + if ( stats_secs == 0 ) + stats_secs = 1; /* fudge */ + stats_time = now; + syslog( LOG_NOTICE, + "up %ld seconds, stats for %ld seconds:", up_secs, stats_secs ); + + thttpd_logstats( stats_secs ); + httpd_logstats( stats_secs ); + mmc_logstats( stats_secs ); + fdwatch_logstats( stats_secs ); + tmr_logstats( stats_secs ); + } + + +/* Generate debugging statistics syslog message. */ +static void +thttpd_logstats( long secs ) + { + if ( secs > 0 ) + syslog( LOG_NOTICE, + " thttpd - %ld connections (%g/sec), %d max simultaneous, %lld bytes (%g/sec), %d httpd_conns allocated", + stats_connections, (float) stats_connections / secs, + stats_simultaneous, (long long) stats_bytes, + (float) stats_bytes / secs, httpd_conn_count ); + stats_connections = 0; + stats_bytes = 0; + stats_simultaneous = 0; + } diff --git a/src/thttpd-2.27/timers.c b/src/thttpd-2.27/timers.c new file mode 100644 index 0000000..908304a --- /dev/null +++ b/src/thttpd-2.27/timers.c @@ -0,0 +1,351 @@ +/* timers.c - simple timer routines +** +** Copyright © 1995,1998,2000,2014 by Jef Poskanzer . +** 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 + +#include +#include +#include + +#include "timers.h" + + +#define HASH_SIZE 67 +static Timer* timers[HASH_SIZE]; +static Timer* free_timers; +static int alloc_count, active_count, free_count; + +ClientData JunkClientData; + + + +static unsigned int +hash( Timer* t ) + { + /* We can hash on the trigger time, even though it can change over + ** the life of a timer via either the periodic bit or the tmr_reset() + ** call. This is because both of those guys call l_resort(), which + ** recomputes the hash and moves the timer to the appropriate list. + */ + return ( + (unsigned int) t->time.tv_sec ^ + (unsigned int) t->time.tv_usec ) % HASH_SIZE; + } + + +static void +l_add( Timer* t ) + { + int h = t->hash; + Timer* t2; + Timer* t2prev; + + t2 = timers[h]; + if ( t2 == (Timer*) 0 ) + { + /* The list is empty. */ + timers[h] = t; + t->prev = t->next = (Timer*) 0; + } + else + { + if ( t->time.tv_sec < t2->time.tv_sec || + ( t->time.tv_sec == t2->time.tv_sec && + t->time.tv_usec <= t2->time.tv_usec ) ) + { + /* The new timer goes at the head of the list. */ + timers[h] = t; + t->prev = (Timer*) 0; + t->next = t2; + t2->prev = t; + } + else + { + /* Walk the list to find the insertion point. */ + for ( t2prev = t2, t2 = t2->next; t2 != (Timer*) 0; + t2prev = t2, t2 = t2->next ) + { + if ( t->time.tv_sec < t2->time.tv_sec || + ( t->time.tv_sec == t2->time.tv_sec && + t->time.tv_usec <= t2->time.tv_usec ) ) + { + /* Found it. */ + t2prev->next = t; + t->prev = t2prev; + t->next = t2; + t2->prev = t; + return; + } + } + /* Oops, got to the end of the list. Add to tail. */ + t2prev->next = t; + t->prev = t2prev; + t->next = (Timer*) 0; + } + } + } + + +static void +l_remove( Timer* t ) + { + int h = t->hash; + + if ( t->prev == (Timer*) 0 ) + timers[h] = t->next; + else + t->prev->next = t->next; + if ( t->next != (Timer*) 0 ) + t->next->prev = t->prev; + } + + +static void +l_resort( Timer* t ) + { + /* Remove the timer from its old list. */ + l_remove( t ); + /* Recompute the hash. */ + t->hash = hash( t ); + /* And add it back in to its new list, sorted correctly. */ + l_add( t ); + } + + +void +tmr_init( void ) + { + int h; + + for ( h = 0; h < HASH_SIZE; ++h ) + timers[h] = (Timer*) 0; + free_timers = (Timer*) 0; + alloc_count = active_count = free_count = 0; + } + + +Timer* +tmr_create( + struct timeval* nowP, TimerProc* timer_proc, ClientData client_data, + long msecs, int periodic ) + { + Timer* t; + + if ( free_timers != (Timer*) 0 ) + { + t = free_timers; + free_timers = t->next; + --free_count; + } + else + { + t = (Timer*) malloc( sizeof(Timer) ); + if ( t == (Timer*) 0 ) + return (Timer*) 0; + ++alloc_count; + } + + t->timer_proc = timer_proc; + t->client_data = client_data; + t->msecs = msecs; + t->periodic = periodic; + if ( nowP != (struct timeval*) 0 ) + t->time = *nowP; + else + (void) gettimeofday( &t->time, (struct timezone*) 0 ); + t->time.tv_sec += msecs / 1000L; + t->time.tv_usec += ( msecs % 1000L ) * 1000L; + if ( t->time.tv_usec >= 1000000L ) + { + t->time.tv_sec += t->time.tv_usec / 1000000L; + t->time.tv_usec %= 1000000L; + } + t->hash = hash( t ); + /* Add the new timer to the proper active list. */ + l_add( t ); + ++active_count; + + return t; + } + + +struct timeval* +tmr_timeout( struct timeval* nowP ) + { + long msecs; + static struct timeval timeout; + + msecs = tmr_mstimeout( nowP ); + if ( msecs == INFTIM ) + return (struct timeval*) 0; + timeout.tv_sec = msecs / 1000L; + timeout.tv_usec = ( msecs % 1000L ) * 1000L; + return &timeout; + } + + +long +tmr_mstimeout( struct timeval* nowP ) + { + int h; + int gotone; + long msecs, m; + Timer* t; + + gotone = 0; + msecs = 0; /* make lint happy */ + /* Since the lists are sorted, we only need to look at the + ** first timer on each one. + */ + for ( h = 0; h < HASH_SIZE; ++h ) + { + t = timers[h]; + if ( t != (Timer*) 0 ) + { + m = ( t->time.tv_sec - nowP->tv_sec ) * 1000L + + ( t->time.tv_usec - nowP->tv_usec ) / 1000L; + if ( ! gotone ) + { + msecs = m; + gotone = 1; + } + else if ( m < msecs ) + msecs = m; + } + } + if ( ! gotone ) + return INFTIM; + if ( msecs <= 0 ) + msecs = 0; + return msecs; + } + + +void +tmr_run( struct timeval* nowP ) + { + int h; + Timer* t; + Timer* next; + + for ( h = 0; h < HASH_SIZE; ++h ) + for ( t = timers[h]; t != (Timer*) 0; t = next ) + { + next = t->next; + /* Since the lists are sorted, as soon as we find a timer + ** that isn't ready yet, we can go on to the next list. + */ + if ( t->time.tv_sec > nowP->tv_sec || + ( t->time.tv_sec == nowP->tv_sec && + t->time.tv_usec > nowP->tv_usec ) ) + break; + (t->timer_proc)( t->client_data, nowP ); + if ( t->periodic ) + { + /* Reschedule. */ + t->time.tv_sec += t->msecs / 1000L; + t->time.tv_usec += ( t->msecs % 1000L ) * 1000L; + if ( t->time.tv_usec >= 1000000L ) + { + t->time.tv_sec += t->time.tv_usec / 1000000L; + t->time.tv_usec %= 1000000L; + } + l_resort( t ); + } + else + tmr_cancel( t ); + } + } + + +void +tmr_reset( struct timeval* nowP, Timer* t ) + { + t->time = *nowP; + t->time.tv_sec += t->msecs / 1000L; + t->time.tv_usec += ( t->msecs % 1000L ) * 1000L; + if ( t->time.tv_usec >= 1000000L ) + { + t->time.tv_sec += t->time.tv_usec / 1000000L; + t->time.tv_usec %= 1000000L; + } + l_resort( t ); + } + + +void +tmr_cancel( Timer* t ) + { + /* Remove it from its active list. */ + l_remove( t ); + --active_count; + /* And put it on the free list. */ + t->next = free_timers; + free_timers = t; + ++free_count; + t->prev = (Timer*) 0; + } + + +void +tmr_cleanup( void ) + { + Timer* t; + + while ( free_timers != (Timer*) 0 ) + { + t = free_timers; + free_timers = t->next; + --free_count; + free( (void*) t ); + --alloc_count; + } + } + + +void +tmr_term( void ) + { + int h; + + for ( h = 0; h < HASH_SIZE; ++h ) + while ( timers[h] != (Timer*) 0 ) + tmr_cancel( timers[h] ); + tmr_cleanup(); + } + + +/* Generate debugging statistics syslog message. */ +void +tmr_logstats( long secs ) + { + syslog( + LOG_NOTICE, " timers - %d allocated, %d active, %d free", + alloc_count, active_count, free_count ); + if ( active_count + free_count != alloc_count ) + syslog( LOG_ERR, "timer counts don't add up!" ); + } diff --git a/src/thttpd-2.27/timers.h b/src/thttpd-2.27/timers.h new file mode 100644 index 0000000..aaa06c6 --- /dev/null +++ b/src/thttpd-2.27/timers.h @@ -0,0 +1,109 @@ +/* timers.h - header file for timers package +** +** Copyright © 1995,1998,1999,2000,2014 by Jef Poskanzer . +** 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 + +#ifndef INFTIM +#define INFTIM -1 +#endif /* INFTIM */ + +/* ClientData is a random value that tags along with a timer. The client +** can use it for whatever, and it gets passed to the callback when the +** timer triggers. +*/ +typedef union { + void* p; + int i; + long l; + } ClientData; + +extern ClientData JunkClientData; /* for use when you don't care */ + +/* The TimerProc gets called when the timer expires. It gets passed +** the ClientData associated with the timer, and a timeval in case +** it wants to schedule another timer. +*/ +typedef void TimerProc( ClientData client_data, struct timeval* nowP ); + +/* The Timer struct. */ +typedef struct TimerStruct { + TimerProc* timer_proc; + ClientData client_data; + long msecs; + int periodic; + struct timeval time; + struct TimerStruct* prev; + struct TimerStruct* next; + int hash; + } Timer; + +/* Initialize the timer package. */ +void tmr_init( void ); + +/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */ +Timer* tmr_create( + struct timeval* nowP, TimerProc* timer_proc, ClientData client_data, + long msecs, int periodic ); + +/* Returns a timeout indicating how long until the next timer triggers. You +** can just put the call to this routine right in your select(). Returns +** (struct timeval*) 0 if no timers are pending. +*/ +struct timeval* tmr_timeout( struct timeval* nowP ); + +/* Returns a timeout in milliseconds indicating how long until the next timer +** triggers. You can just put the call to this routine right in your poll(). +** Returns INFTIM (-1) if no timers are pending. +*/ +long tmr_mstimeout( struct timeval* nowP ); + +/* Run the list of timers. Your main program needs to call this every so often, +** or as indicated by tmr_timeout(). +*/ +void tmr_run( struct timeval* nowP ); + +/* Reset the clock on a timer, to current time plus the original timeout. */ +void tmr_reset( struct timeval* nowP, Timer* timer ); + +/* Deschedule a timer. Note that non-periodic timers are automatically +** descheduled when they run, so you don't have to call this on them. +*/ +void tmr_cancel( Timer* timer ); + +/* Clean up the timers package, freeing any unused storage. */ +void tmr_cleanup( void ); + +/* Cancel all timers and free storage, usually in preparation for exiting. */ +void tmr_term( void ); + +/* Generate debugging statistics syslog message. */ +void tmr_logstats( long secs ); + +#endif /* _TIMERS_H_ */ diff --git a/src/thttpd-2.27/version.h b/src/thttpd-2.27/version.h new file mode 100644 index 0000000..7638cb5 --- /dev/null +++ b/src/thttpd-2.27/version.h @@ -0,0 +1,9 @@ +/* version.h - version defines for thttpd and libhttpd */ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + +#define SERVER_SOFTWARE "thttpd/2.27 19Oct2015" +#define SERVER_ADDRESS "http://www.acme.com/software/thttpd/" + +#endif /* _VERSION_H_ */ diff --git a/src/vtx2ascii-src/Makefile b/src/vtx2ascii-src/Makefile new file mode 100644 index 0000000..2e44aef --- /dev/null +++ b/src/vtx2ascii-src/Makefile @@ -0,0 +1,17 @@ + +CC=gcc +CFLAGS=-Wall -g -O2 -I. + +PROG=vtx2ascii + +$(PROG): main.o fileio.o vtxtools.o vtxdecode.o + $(CC) $(CFLAGS) -o $@ $^ + +clean: + rm -f *.o *~ + +distclean: clean + strip $(PROG) + +realclean: clean + rm -f $(PROG) diff --git a/src/vtx2ascii-src/README b/src/vtx2ascii-src/README new file mode 100644 index 0000000..c3e85bf --- /dev/null +++ b/src/vtx2ascii-src/README @@ -0,0 +1,24 @@ + +'make' should build the whole thing. + +vtx2ascii is a simple converter, build out of the videotext sources. +In fact only the main.c is my work, all other C code is just copyed +from the videotext package. Start it without arguments to get help. + +vtx.cgi is a cgi script for converting vtx-pages on-the-fly. Lynx +approved, with netscape 4 (style sheets required) you'll get colors. +Uses vtx2ascii. You have to adjust two config lines at the top of +the script. Usage is very simple, just copy it to your server's +cgi-bin directory and point your browser to it. If you want, you +can hide it with a Alias like this one: + ScriptAlias /videotext /home/www/cgi/vtx.cgi # in srm.conf + +vtx.cgi delivers a correct last-modified header (=> cacheable pages) +for fast browsing. For script hacking you probably want to turn this +off... + +Known issues: can't show hidden text, 8-bit chars don't work (wrong +mapping), probably more. It is'nt tested much, sort of prototype. + + Gerd + diff --git a/src/vtx2ascii-src/cct.h b/src/vtx2ascii-src/cct.h new file mode 100644 index 0000000..6846771 --- /dev/null +++ b/src/vtx2ascii-src/cct.h @@ -0,0 +1,38 @@ +#ifndef CCT_H_INCLUDED +#define CCT_H_INCLUDED + +/* $Id: cct.h,v 1.1 1996/09/22 22:37:43 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + */ + + +#include + + +#define CCTOK 0 +#define CCTNOTFOUND 1 +#define CCTERR -1 +#define CCTEINVAL -2 +#define CCTEOPEN -3 +#define CCTEVERSION -4 +#define CCTENOTOPEN -5 + + +extern char *cct_device; + +int cct_open(int major, int minor, vtx_info_t *prg_info); +void cct_close(void); +int cct_clearpgbuf(int pgbuf); +int cct_checkpage(int pgbuf); +int cct_stop_dau(int pgbuf); +int cct_reset_pgfound(int pgbuf); +int cct_searchpage(int page, int hour, int minute, int pagemask, int pgbuf); +int cct_getpage(int pgbuf, int x1, int y1, int x2, int y2, byte_t *buffer, vtx_pageinfo_t *info); +int cct_putpage(int x1, int y1, int x2, int y2, const byte_t *buffer, const vtx_pageinfo_t *info); +int cct_set_display(vtxdisp_t disp); +int cct_clear_cache(void); +int cct_set_virtual(int virtual); + +#endif /* CCT_H_INCLUDED */ diff --git a/src/vtx2ascii-src/fileio.c b/src/vtx2ascii-src/fileio.c new file mode 100644 index 0000000..5c59237 --- /dev/null +++ b/src/vtx2ascii-src/fileio.c @@ -0,0 +1,163 @@ +/* + * fileio.c: Read font-bitmaps, write GIF-, PPM-, ASCII- & VTX-files + * + * $Id: fileio.c,v 1.5 1997/08/14 22:59:42 mb Exp mb $ + * + * Copyright (c) 1995-96 Martin Buck + * Read COPYING for more information + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "vtx_assert.h" +#include "vtxdecode.h" +#include "vtxtools.h" +#include "misc.h" +#include "fileio.h" + +#define VTXFONT_EXT ".vtxfont" +typedef enum { FP_ARG, FP_ENV, FP_DEFAULT } fp_src_t; + + +char *vtx_fontpath; + + +static const int vtx_img_red[8] = { 0, 255, 0, 255, 0, 255, 0, 255 }; +static const int vtx_img_green[8] = { 0, 0, 255, 255, 0, 0, 255, 255 }; +static const int vtx_img_blue[8] = { 0, 0, 0, 0, 255, 255, 255, 255 }; + +static const vtxpage_t *vtxpage; +static const vtxbmfont_t *vtxfont; +static int reveal; + + + +void +export_ascii(FILE *file, const vtxpage_t *page, int show_hidden) { + int pos; + + for (pos = 0; pos < VTX_PAGESIZE; pos++) { + if (!(page->attrib[pos] & VTX_HIDDEN) || show_hidden) { + fputc(vtx2iso_table[page->chr[pos]], file); + } else { + fputc(' ', file); + } + if (pos % 40 == 39) + fputc('\n', file); + } +} + + +void +save_vtx(FILE *file, const byte_t *buffer, const vtx_pageinfo_t *info, int virtual) { + fputs("VTXV4", file); + fputc(info->pagenum & 0xff, file); + fputc(info->pagenum / 0x100, file); + fputc(info->hour & 0xff, file); + fputc(info->minute & 0xff, file); + fputc(info->charset & 0xff, file); + fputc(info->delete << 7 | info->headline << 6 | info->subtitle << 5 | info->supp_header << 4 | + info->update << 3 | info->inter_seq << 2 | info->dis_disp << 1 | info->serial << 0, file); + fputc(info->notfound << 7 | info->pblf << 6 | info->hamming << 5 | (!!virtual) << 4 | + 0 << 3, file); + fwrite(buffer, 1, virtual ? VTX_VIRTUALSIZE : VTX_PAGESIZE, file); +} + + +int +load_vtx(FILE *file, byte_t *buffer, vtx_pageinfo_t *info, int *virtual) { + byte_t tmp_buffer[VTX_VIRTUALSIZE]; + vtx_pageinfo_t tmp_inf; + unsigned char tmpstr[256]; + struct stat st; + int pos, tmpbits, is_virtual = FALSE, is_sevenbit = FALSE; + + memset(tmp_buffer, ' ', sizeof(tmp_buffer)); + if (fscanf(file, "VTXV%c", tmpstr) != 1) { + if (fstat(fileno(file), &st) < 0) { + return LOADERR; + /* The stupid INtv format doesn't use a signature, so we have to use the file-length instead */ + } else if (st.st_size != 1008) { + return LOADEMAGIC; + } + memset(&tmp_inf, 0, sizeof(tmp_inf)); /* Read ITV-file */ + rewind(file); + for (pos = 0; pos <= 23; pos++) { + fseek(file, 2, SEEK_CUR); + fread(tmp_buffer + pos * 40, 40, 1, file); + } + /* The first 8 bytes in the INtv-format usually contain garbage (or data I don't understand) */ + memset(tmp_buffer, vtx_mkparity(' '), 8 * sizeof(byte_t)); + for (pos = 0; pos <= 2; pos++) { + tmpstr[pos] = tmp_buffer[8 + pos]; + vtx_chkparity(&tmpstr[pos]); + } + tmpstr[3] = '\0'; + sscanf(tmpstr, "%3x", &tmp_inf.pagenum); + if (!vtx_chkpgnum(tmp_inf.pagenum, TRUE)) { + tmp_inf.pagenum = 0; + } + if (virtual) { + *virtual = FALSE; + } + } else { + if (tmpstr[0] != '2' && tmpstr[0] != '3' && tmpstr[0] != '4') { + return LOADEVERSION; + } + tmp_inf.pagenum = fgetc(file) + 0x100 * fgetc(file); /* Read VTX-file */ + tmp_inf.hour = fgetc(file); + tmp_inf.minute = fgetc(file); + tmp_inf.charset = fgetc(file); + tmpbits = fgetc(file); + tmp_inf.delete = !!(tmpbits & 0x80); + tmp_inf.headline = !!(tmpbits & 0x40); + tmp_inf.subtitle = !!(tmpbits & 0x20); + tmp_inf.supp_header = !!(tmpbits & 0x10); + tmp_inf.update = !!(tmpbits & 8); + tmp_inf.inter_seq = !!(tmpbits & 4); + tmp_inf.dis_disp = !!(tmpbits & 2); + tmp_inf.serial = (tmpbits & 1); + tmpbits = fgetc(file); + tmp_inf.notfound = !!(tmpbits & 0x80); + tmp_inf.pblf = !!(tmpbits & 0x40); + tmp_inf.hamming = !!(tmpbits & 0x20); + if (tmpstr[0] == '3') { + is_virtual = TRUE; + } else if (tmpstr[0] == '4') { + is_virtual = !!(tmpbits & 0x10); + is_sevenbit = !!(tmpbits & 8); + } + fread(tmp_buffer, is_virtual ? VTX_VIRTUALSIZE : VTX_PAGESIZE, 1, file); + if (virtual) { + *virtual = is_virtual; + } + } + if (feof(file)) { + return LOADECORRUPT; + } + if (ferror(file)) { + return LOADERR; + } + if (buffer) { + /* If file was saved in seven-bit mode, fake parity bit. + * FIXME: Should we add parity to the virtual part too? + */ + if (is_sevenbit) { + for (pos = 0; pos < VTX_PAGESIZE; pos++) { + tmp_buffer[pos] = vtx_mkparity(tmp_buffer[pos]); + } + } + memcpy(buffer, tmp_buffer, is_virtual ? VTX_VIRTUALSIZE : VTX_PAGESIZE); + memset(buffer, vtx_mkparity(7), 8); + } + if (info) { + *info = tmp_inf; + } + return LOADOK; +} diff --git a/src/vtx2ascii-src/fileio.h b/src/vtx2ascii-src/fileio.h new file mode 100644 index 0000000..f2d55a0 --- /dev/null +++ b/src/vtx2ascii-src/fileio.h @@ -0,0 +1,47 @@ +#ifndef VTXBITMAP_H_INCLUDED +#define VTXBITMAP_H_INCLUDED + +/* $Id: fileio.h,v 1.3 1997/08/14 23:00:12 mb Exp mb $ + * + * Copyright (c) 1995-96 Martin Buck + * Read COPYING for more information + */ + + +#include +#include "vtxdecode.h" + + +#define BITS_PER_BYTE 8 + +#define LOADOK 0 +#define LOADERR -1 +#define LOADEMAGIC -2 +#define LOADEVERSION -3 +#define LOADECORRUPT -4 + + +typedef struct { + int xsize, ysize, bpr, bpc; + unsigned char *bitmap; +} vtxbmfont_t; + + +extern char *vtx_fontpath; + + +vtxbmfont_t * read_font(unsigned int xsize, unsigned int ysize); +#ifdef GIF_SUPPORT +void export_gif(FILE *file, const vtxpage_t *page, const vtxbmfont_t *font, int interlace, + int show_hidden); +#endif +void export_ppm(FILE *file, const vtxpage_t *page, const vtxbmfont_t *font, int show_hidden); +#ifdef PNG_SUPPORT +int export_png(FILE *file, const vtxpage_t *page, const vtxbmfont_t *font, int interlace, + int show_hidden, char ***msg_list); +#endif +void export_ascii(FILE *file, const vtxpage_t *page, int show_hidden); +void save_vtx(FILE *file, const byte_t *buffer, const vtx_pageinfo_t *info, int virtual); +int load_vtx(FILE *file, byte_t *buffer, vtx_pageinfo_t *info, int *virtual); + +#endif /* VTXBITMAP_H_INCLUDED */ diff --git a/src/vtx2ascii-src/main.c b/src/vtx2ascii-src/main.c new file mode 100644 index 0000000..2c83864 --- /dev/null +++ b/src/vtx2ascii-src/main.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include + +#include "fileio.h" + +unsigned char buffer[65536]; +vtxpage_t page; +int virtual; + +#define OUT_ASCII 1 +#define OUT_ANSI 2 +#define OUT_HTML 3 + +void +export_ansi_ascii(FILE *file, const vtxpage_t *page, int show_hidden) +{ + int pos; + int bg,fg,lbg,lfg,hidden; + + lfg = lbg = -1; + for (pos = 0; pos < VTX_PAGESIZE; pos++) { + fg = page->attrib[pos] & VTX_COLMASK; + bg = (page->attrib[pos] & VTX_BGMASK) >> 3; + hidden = (page->attrib[pos] & VTX_HIDDEN) && !show_hidden; + if (fg != lfg || bg != lbg) { + fprintf(file,"\033[%d;%dm",fg+30,bg+40); + lfg = fg; + lbg = bg; + } + fputc(hidden ? ' ' : vtx2iso_table[page->chr[pos]], file); + if (pos % 40 == 39) { + lfg = lbg = -1; + fprintf(file,"\033[0m\n"); + } + } +} + +void +export_html(FILE *file, const vtxpage_t *page, int show_hidden) +{ + static const char *color[] = { + "black", "red", "green", "yellow", + "blue", "magenta", "cyan", "white" + }; + + int pos; + int bg,fg,lbg,lfg,hidden; + int used[64]; + + /* scan for used colors */ + memset(used,0,sizeof(used)); + for (pos = 0; pos < VTX_PAGESIZE; pos++) { + fg = page->attrib[pos] & VTX_COLMASK; + bg = (page->attrib[pos] & VTX_BGMASK) >> 3; + used[fg*8+bg] = 1; + } + + /* print styles */ + fprintf(file,"\n"); + + /* print page */ + fprintf(file,"
\n");
+	lfg = lbg = -1;
+	for (pos = 0; pos < VTX_PAGESIZE; pos++) {
+		fg     =  page->attrib[pos] & VTX_COLMASK;
+		bg     = (page->attrib[pos] & VTX_BGMASK) >> 3;
+		hidden = (page->attrib[pos] & VTX_HIDDEN) && !show_hidden;
+		if (fg != lfg || bg != lbg) {
+			if (lfg != -1 || lbg != -1)
+				fprintf(file,"");
+			fprintf(file,"",fg*8+bg);
+			lfg = fg;
+			lbg = bg;
+		}
+		fputc(hidden ? ' ' : vtx2iso_table[page->chr[pos]], file);
+		if (pos % 40 == 39) {
+			lfg = lbg = -1;
+			fprintf(file,"\n");
+		}
+	}
+	fprintf(file,"
\n"); +} + +void +usage(char *prog) +{ + fprintf(stderr,"usage: %s [ options ] vtx-file\n",prog); + fprintf(stderr, + "options: \n" + " -a dump plain ascii (default)\n" + " -c dump colored ascii (using ansi control sequences).\n" + " -h dump html\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + char *prog; + int c,output=OUT_ASCII; + + if (NULL != (prog = strrchr(argv[0],'/'))) + prog++; + else + prog = argv[0]; + + for (;;) { + if (-1 == (c = getopt(argc, argv, "ach"))) + break; + switch (c) { + case 'a': + output=OUT_ASCII; + break; + case 'c': + output=OUT_ANSI; + break; + case 'h': + output=OUT_HTML; + break; + default: + usage(prog); + } + } + if (optind+1 != argc) + usage(prog); + + if (NULL == (fp = fopen(argv[optind],"r"))) { + fprintf(stderr,"%s: %s: %s\n",prog,argv[optind],strerror(errno)); + exit(1); + } + + load_vtx(fp, buffer, &page.info, &virtual); + decode_page(buffer, &page, 0, 23); + switch(output) { + case OUT_ASCII: + export_ascii(stdout, &page, 0); + break; + case OUT_ANSI: + export_ansi_ascii(stdout, &page, 0); + break; + case OUT_HTML: + export_html(stdout, &page, 0); + break; + } + return 0; +} diff --git a/src/vtx2ascii-src/misc.h b/src/vtx2ascii-src/misc.h new file mode 100644 index 0000000..8039941 --- /dev/null +++ b/src/vtx2ascii-src/misc.h @@ -0,0 +1,41 @@ +#ifndef MISC_H_INCLUDED +#define MISC_H_INCLUDED + +/* $Id: misc.h,v 1.1 1996/10/14 21:37:00 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + */ + +#include + + +#define VTXVERSION "0.6.970815" +#define VTXNAME "videotext" +#define VTXCLASS "Videotext" +#define VTXWINNAME "VideoteXt" + +#define REQ_MAJOR 1 +#define REQ_MINOR 6 + + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#define SIGN(a) ((a) < 0 ? -1 : ((a) > 0 ? 1 : 0)) +#define STRINGIFY_NOMACRO(str) #str +#define STRINGIFY(str) STRINGIFY_NOMACRO(str) +#define NELEM(a) (sizeof(a) / sizeof(*(a))) + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +/* It's unbelievable that some systems are unable to provide the most basic ANSI-C features */ +#ifndef INT_MAX +#define INT_MAX 2147483647 +#endif + +#endif /* MISC_H_INCLUDED */ diff --git a/src/vtx2ascii-src/sys/vtx.h b/src/vtx2ascii-src/sys/vtx.h new file mode 100644 index 0000000..c1b4fec --- /dev/null +++ b/src/vtx2ascii-src/sys/vtx.h @@ -0,0 +1,151 @@ +#ifndef VTX_H_INCLUDED +#define VTX_H_INCLUDED + +/* $Id: vtx.h,v 1.6 1997/08/09 00:40:49 mb Exp mb $ + * + * Copyright (c) 1994-97 Martin Buck + * Read COPYING for more information + * + */ + + +typedef unsigned char byte_t; + + +/* videotext ioctls + */ +#define VTXIOCGETINFO 0x7101 /* get version of driver & capabilities of vtx-chipset */ +#define VTXIOCCLRPAGE 0x7102 /* clear page-buffer */ +#define VTXIOCCLRFOUND 0x7103 /* clear bits indicating that page was found */ +#define VTXIOCPAGEREQ 0x7104 /* search for page */ +#define VTXIOCGETSTAT 0x7105 /* get status of page-buffer */ +#define VTXIOCGETPAGE 0x7106 /* get contents of page-buffer */ +#define VTXIOCSTOPDAU 0x7107 /* stop data acquisition unit */ +#define VTXIOCPUTPAGE 0x7108 /* display page on TV-screen */ +#define VTXIOCSETDISP 0x7109 /* set TV-mode */ +#define VTXIOCPUTSTAT 0x710a /* set status of TV-output-buffer */ +#define VTXIOCCLRCACHE 0x710b /* clear cache on VTX-interface (if avail.) */ +#define VTXIOCSETVIRT 0x710c /* turn on virtual mode (this disables TV-display) */ +#define VTXIOCGETQUAL 0x710d /* get current video/videotext quality */ + + +/* definitions for VTXIOCGETINFO + */ +#define SAA5243 0 +#define SAA5246 1 +#define SAA5249 2 +#define SAA5248 3 +#define XSTV5346 4 + +typedef struct { + int version_major, version_minor; /* version of driver; if version_major changes, driver */ + /* is not backward compatible!!! CHECK THIS!!! */ + int numpages; /* number of page-buffers of vtx-chipset */ + int cct_type; /* type of vtx-chipset (SAA5243, SAA5246, SAA5248 or + * SAA5249) */ +} vtx_info_t; + + +/* definitions for VTXIOC{CLRPAGE,CLRFOUND,PAGEREQ,GETSTAT,GETPAGE,STOPDAU,PUTPAGE,SETDISP} + */ +#define MIN_UNIT (1<<0) +#define MIN_TEN (1<<1) +#define HR_UNIT (1<<2) +#define HR_TEN (1<<3) +#define PG_UNIT (1<<4) +#define PG_TEN (1<<5) +#define PG_HUND (1<<6) +#define PGMASK_MAX (1<<7) +#define PGMASK_PAGE (PG_HUND | PG_TEN | PG_UNIT) +#define PGMASK_HOUR (HR_TEN | HR_UNIT) +#define PGMASK_MINUTE (MIN_TEN | MIN_UNIT) + +typedef struct { + int page; /* number of requested page (hexadecimal) */ + int hour; /* requested hour (hexadecimal) */ + int minute; /* requested minute (hexadecimal) */ + int pagemask; /* mask defining which values of the above are set */ + int pgbuf; /* buffer where page will be stored */ + int start; /* start of requested part of page */ + int end; /* end of requested part of page */ + void* buffer; /* pointer to beginning of destination buffer */ +} vtx_pagereq_t; + + +/* definitions for VTXIOC{GETSTAT,PUTSTAT} + */ +#define VTX_PAGESIZE (40 * 24) +#define VTX_VIRTUALSIZE (40 * 49) + +typedef struct { + int pagenum; /* number of page (hexadecimal) */ + int hour; /* hour (hexadecimal) */ + int minute; /* minute (hexadecimal) */ + int charset; /* national charset */ + unsigned delete : 1; /* delete page (C4) */ + unsigned headline : 1; /* insert headline (C5) */ + unsigned subtitle : 1; /* insert subtitle (C6) */ + unsigned supp_header : 1; /* suppress header (C7) */ + unsigned update : 1; /* update page (C8) */ + unsigned inter_seq : 1; /* interrupted sequence (C9) */ + unsigned dis_disp : 1; /* disable/suppress display (C10) */ + unsigned serial : 1; /* serial mode (C11) */ + unsigned notfound : 1; /* /FOUND */ + unsigned pblf : 1; /* PBLF */ + unsigned hamming : 1; /* hamming-error occured */ +} vtx_pageinfo_t; + + +/* definitions for VTXIOCSETDISP + */ +typedef enum { DISPOFF, DISPNORM, DISPTRANS, DISPINS, INTERLACE_OFFSET } vtxdisp_t; + + +/* definitions for VTXIOCGETQUAL + */ +typedef struct { + int video; + int videotext; +} vtx_quality_t; + + +/* tuner ioctls + */ +#define TUNIOCGETINFO 0x7201 /* get version of driver & capabilities of tuner */ +#define TUNIOCRESET 0x7202 /* reset tuner */ +#define TUNIOCSETFREQ 0x7203 /* set tuning frequency (unit: kHz) */ +#define TUNIOCGETFREQ 0x7204 /* get tuning frequency (unit: kHz) */ +#define TUNIOCSETPROG 0x7205 /* set tuning program */ +#define TUNIOCGETPROG 0x7206 /* get tuning program */ + + +typedef struct { + int version_major, version_minor; /* version of driver; if version_major changes, driver */ + /* is not backward compatible!!! CHECK THIS!!! */ + unsigned freq : 1; /* tuner can be set to arbitrary frequency */ + unsigned prog : 1; /* tuner stores several programs */ + unsigned scan : 1; /* tuner supports scanning */ + unsigned autoscan : 1; /* tuner supports scanning with automatic stop */ + unsigned afc : 1; /* tuner supports AFC */ + unsigned dummy1, dummy2, dummy3, dummy4, dummy5, dummy6, dummy7, dummy8, dummy9, dummy10, + dummy11 : 1; + int dummy12, dummy13, dummy14, dummy15, dummy16, dummy17, dummy18, dummy19; +} tuner_info_t; + + +/* i2c ioctls + */ + +#define I2CIOCWRITE 0x7300 /* write raw data to I²C-bus (needs RAW_I2C_SUPPORT) */ +#define I2CIOCREAD 0x7301 /* read raw data from I²C-bus (needs RAW_I2C_SUPPORT) */ + + +/* definitions for I2CIOC{WRITE,READ} + */ +typedef struct { + int adr; + int count; + byte_t *buffer; +} i2c_raw_t; + +#endif /* VTX_H_INCLUDED */ diff --git a/src/vtx2ascii-src/vtx.cgi b/src/vtx2ascii-src/vtx.cgi new file mode 100755 index 0000000..d921f05 --- /dev/null +++ b/src/vtx2ascii-src/vtx.cgi @@ -0,0 +1,140 @@ +#!/usr/bin/perl +use CGI; + +# config +$SPOOL="/home/kraxel/vtx"; +$VTX2ASCII="/home/kraxel/bin/vtx2ascii"; + +####################################################################### +# create time string + +@WEEK = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); +@MON = ('Jan','Feb','Mar','Apr','May','Jun', + 'Jul','Aug','Sep','Oct','Nov','Dec'); + +sub time2str { + @tm = gmtime($_[0]); + sprintf ("%s, %02d %s %04d %02d:%02d:%02d GMT", + $WEEK[$tm[6]],$tm[3],$MON[$tm[4]],$tm[5]+1900,$tm[2],$tm[1],$tm[0]); +} + +####################################################################### +# helper functions + +sub start_page { + local($title,$file) = @_; + + if ($file ne "") { + @inode = stat $file; + printf("Last-modified: %s\n",time2str(@inode[9])); + } + print < + +videotext: $title + + +EOF +} + +sub finish_page { + print "\n"; +} + +sub panic { + local($text) = @_; + + start_page("PANIC"); + print "

PANIC

$text"; + &finish_page; + exit; +} + +sub addlink() { + local($nr) = @_; + + $links{$nr} = 1; + return $nr; +} + +####################################################################### +# main + +$cgi = new CGI; + +if ($cgi->path_info eq "" || $cgi->path_info =~ /^\/[^\/]+$/) { + print $cgi->redirect($cgi->url . $cgi->path_info . "/"); + exit; +} +($dummy,$station,$page) = split(/\//,$cgi->path_info); + +# entry page - station list +if ($station !~ /\S/) { + opendir DIR, $SPOOL || panic("can't open dir $SPOOL: $@"); + &start_page("station list",$SPOOL); + print "

station list

\n
    \n"; + while ($file = readdir(DIR)) { + next if ($file =~ /^\./); + next unless -d "$SPOOL/$file"; + print "
  • $file\n"; + } + print "
\n"; + &finish_page; + exit; +} + +# station dir - spage list +if ($page !~ /\S/) { + opendir DIR, "$SPOOL/$station" || + panic("can't open dir $SPOOL/$station: $@"); + &start_page("$station - page list","$SPOOL/$station"); + print "

$station - page list

\n\n"; + print "[station list]
    \n"; + while ($file = readdir(DIR)) { + next unless ($file =~ /\.vtx/); + print "
  • $file\n"; + } + print "
\n"; + &finish_page; + exit; +} + +# print page +unless (-f "$SPOOL/$station/$page") { + # sub-page check + if ($page =~ s/_00.vtx/_01.vtx/ && -f "$SPOOL/$station/$page") { + print $cgi->redirect($cgi->url . "/$station/$page"); + exit; + } + panic("$SPOOL/$station/$page: not found"); +} + +# read +undef $/; +open VTX,"$VTX2ASCII -h $SPOOL/$station/$page |" || + panic("can't run $VTX2ASCII: $@"); +$data = ; +close VTX; + +# look for links +$data =~ s/(\d\d\d)/&addlink($1)/eg; + +# print +start_page("$station - $page","$SPOOL/$station/$page"); +print "

$station - $page

\n"; +print "[station list]   "; +print "[page list]   "; +if ($page =~ /(\d\d\d)_(\d\d).vtx/ && $2 > 0) { + printf "[prev subpage]   ",$1,$2-1; + printf "[next subpage]   ",$1,$2+1; +} +print "
\n"; +foreach $item (sort keys %links) { + print "$item\n"; +} +print "
\n"; +print "$data"; +&finish_page; +exit; diff --git a/src/vtx2ascii-src/vtx_assert.h b/src/vtx2ascii-src/vtx_assert.h new file mode 100644 index 0000000..e4dce2a --- /dev/null +++ b/src/vtx2ascii-src/vtx_assert.h @@ -0,0 +1,46 @@ +/* $Id: vtx_assert.h,v 1.1 1996/10/01 21:25:20 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + */ + +/* This header file provides an alternative to the standard assert: You can + * choose wheter or not your program should dump core when an assertion + * fails. If you don't define ASSERT_DUMP_CORE, your program will print the + * `failed assertion'-message and call exit(1) without a coredump. + * + * The reason for this is that you can lock up your X-server when assert + * calls abort() at the wrong time (probably during grabs). If you can't + * login on a serial line or over the network to kill the X-server, you will + * have to reboot your machine (I once experienced this with another + * application -- not even XFree's ZapServer-key did work)! + * + * There has been a report that in VideoteXt an assertion fails when a + * station broadcasts a multipage-extension-table. I wasn't able to + * reproduce this and I don't think that this was the reason for the abort, + * but I decided to use this alternative assert just to make sure VideoteXt + * doesn't do bad things[tm] to your machine :-) + * + * But if you get `failed assertion'-messages, *please* report them to me! + */ + +#include + +#undef assert +#undef __assert + +#ifdef NDEBUG +#define assert(ignore) ((void) 0) +#else + +#define assert(exp) ((void) ((exp) ? 0 : __assert (#exp, __FILE__, __LINE__))) + +#ifdef ASSERT_DUMP_CORE +#define __assert(exp, file, lineno) \ + (fprintf (stderr, "%s:%u: failed assertion `%s'\n", file, lineno, exp), abort (), 0) +#else +#define __assert(exp, file, lineno) \ + (fprintf (stderr, "%s:%u: failed assertion `%s'\nTerminating\n", file, lineno, exp), \ + exit (1), 0) +#endif +#endif diff --git a/src/vtx2ascii-src/vtxdecode.c b/src/vtx2ascii-src/vtxdecode.c new file mode 100644 index 0000000..4ad0d1f --- /dev/null +++ b/src/vtx2ascii-src/vtxdecode.c @@ -0,0 +1,210 @@ +/* + * vtxdecode.c: Routines to decode VTX-pages & convert from magic-cookie-VTX-attributes to + * 'normal' attributes usable by x_vtx_redraw() + * + * $Id: vtxdecode.c,v 1.2 1997/03/26 00:16:54 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + * + */ + +#include +#include "vtx_assert.h" +#include "cct.h" +#include "vtxtools.h" +#include "misc.h" +#include "vtxdecode.h" + + +/* Translation tables to convert VTX font-layout (with different national charsets) to + * X-Window font layout + */ +const chr_t cct2vtx_table[8][96] = { + /* English */ + { 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f }, + /* French */ + { 0x20,0x21,0x22,0Xc0,0Xc1,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0Xc2,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0Xc3,0Xc4,0Xc5,0Xc6,0x5f, + 0Xc7,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0Xc8,0Xc9,0Xca,0Xcb,0x7f }, + /* Swedish */ + { 0x20,0x21,0x22,0X5f,0Xcc,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0Xcd,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0Xce,0Xcf,0Xd0,0Xd1,0Xd2, + 0Xc0,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0Xd3,0Xd4,0Xd5,0Xd6,0x7f }, + /* Unknown */ + { 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f }, + /* German */ + { 0x20,0x21,0x22,0X5f,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0Xd7,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0Xce,0Xcf,0Xd1,0Xd8,0Xd2, + 0Xd9,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0Xd3,0Xd4,0Xd6,0Xda,0x7f }, + /* Spanish */ + { 0x20,0x21,0x22,0Xcb,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0Xcb,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0Xde,0Xc0,0Xdf,0Xe2,0Xe3, + 0Xdc,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0Xd6,0Xdd,0Xc7,0Xc2,0x7f }, + /* Italian */ + { 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0Xc0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0Xd9,0Xcb,0x5d,0x5e,0x5f, + 0Xc5,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0Xc2,0Xe0,0Xc7,0Xe1,0x7f }, + /* Unknown */ + { 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f } +}; + + +/* Translation table to convert VideoteXt-X-Window font-layout to ISO 8859-1. + * You should have a complete ISO-Font when editing the following table! + */ +const char vtx2iso_table[256] = + " " + " !\"#$%&'()*+,-./0123456789:;<=>?" //" !\"£$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" //"@ABCDEFGHIJKLMNOPQRSTUVWXYZ<½>^#" + "`abcdefghijklmnopqrstuvwxyz{|}~ " //"-abcdefghijklmnopqrstuvwxyz¼|¾÷#" + " " + " " //TODO: completely wrong + "éïàëêùîèâôûç¤ÉÄÖÅÜ_äöåü§^°ß¡¿ñáí" //TODO: completely wrong + "òìóú ? ";//TODO: completely wrong +/* The same table with all characters mapped to lowercase */ +const char vtx2iso_lc_table[256] = + " " + " !\"#$%&'()*+,-./0123456789:;<=>?" //" !\"£$%&'()*+,-./0123456789:;<=>?" + "@abcdefghijklmnopqrstuvwxyz[\\]^_" //"@abcdefghijklmnopqrstuvwxyz<½>^#" + "`abcdefghijklmnopqrstuvwxyz{|}~ " //"-abcdefghijklmnopqrstuvwxyz¼|¾÷#" + " " + " " //TODO: completely wrong + "éïàëêùîèâôûç¤Éäöåü_äöåü§^°ß¡¿ñáí" //TODO: completely wrong + "òìóú ? ";//TODO: completely wrong +/* All word delimiters in videotext's subset of ISO 8859-1 */ +//const char vtxiso_worddelim[] = " !\"£$%&'()*+,-./:;<=>?@<½>^#-¼|¾÷¤_§^°¡¿"; +const char vtxiso_worddelim[] = " !\"#$%&'()*+,-./:;<=>?@<\\>^_`{|}~¤_§^°¡¿"; + + +/* Decode lines y1 - y2 of original VTX-page in pgbuf to vtxpage usable by VideoteXt using + * national charset lang + * Return VTXOK if OK, VTXEINVAL if start-/end-line invalid + */ +int +decode_page(const byte_t *pgbuf, vtxpage_t *page, int y1, int y2) { + int line, col, pos, graphics, grhold, doubleht, nextattr = 0; + static int lang; + attrib_t *lastattr, default_attrib = 7, next_attrib; + chr_t chr, *lastchr, default_chr = ' '; + + if (y1 > y2 || y1 < 0 || y2 > 23) + return VTXEINVAL; + + if (!page->info.hamming) + lang = page->info.charset; + + pos = y1 * 40; + doubleht = 0; + for (line = y1; line <= y2; line++) { + lastchr = &default_chr; + lastattr = &default_attrib; + graphics = grhold = 0; + if (doubleht) { + for (col = 0; col <= 39; col++) { + if (page->attrib[pos - 40] & VTX_DOUBLE1) { + page->chr[pos] = page->chr[pos - 40]; + page->chr[pos - 40] = ' '; + page->attrib[pos] = (page->attrib[pos - 40] & ~VTX_DOUBLE1) | VTX_DOUBLE2; + } else { + page->chr[pos] = ' '; + page->attrib[pos] = page->attrib[pos - 40]; + } + pos++; + } + doubleht = 0; + } else { + for (col = 0; col <= 39; col++) { + chr = pgbuf[pos]; + if (!vtx_chkparity(&chr)) { + page->chr[pos] = 254; /* Parity error */ + page->attrib[pos] = 7; + } else if (chr >= 32 && chr <= 127) { /* Normal character */ + page->attrib[pos] = *lastattr; + if (!graphics || (chr >= 64 && chr <= 95)) { + page->chr[pos] = cct2vtx_table[lang][chr - 32]; + } else { + page->chr[pos] = chr + (chr >= 96 ? 64 : 96); + } + } else { + page->chr[pos] = ((grhold && graphics ) ? *lastchr : ' '); + if (chr <= 7) { /* Set alphanumerics-color */ + page->attrib[pos] = *lastattr; + next_attrib = (*lastattr & ~(VTX_COLMASK | VTX_HIDDEN)) + chr; + nextattr = 1; + graphics = 0; + } else if (chr == 8 || chr == 9) { /* Flash on/off */ + page->attrib[pos] = (*lastattr & ~VTX_FLASH) + VTX_FLASH * (chr == 8); + } else if (chr == 10 || chr == 11) { /* End/start box */ + page->attrib[pos] = (*lastattr & ~VTX_BOX) + VTX_BOX * (chr == 11); + } else if (chr == 12 || chr == 13) { /* Normal/double height */ + page->attrib[pos] = (*lastattr & ~VTX_DOUBLE1) + VTX_DOUBLE1 * (chr == 13); + if (chr == 13) + doubleht = 1; + } else if (chr == 14 || chr == 15 || chr == 27) { /* SO, SI, ESC (ignored) */ + page->attrib[pos] = *lastattr; + } else if (chr >= 16 && chr <= 23) { /* Set graphics-color */ + page->attrib[pos] = *lastattr; + next_attrib = (*lastattr & ~(VTX_COLMASK | VTX_HIDDEN)) + chr - 16; + nextattr = 1; + graphics = 1; + } else if (chr == 24) { /* Conceal display */ + page->attrib[pos] = *lastattr | VTX_HIDDEN; + } else if (chr == 25 || chr == 26) { /* Contiguous/separated graphics */ + page->attrib[pos] = (*lastattr & ~VTX_GRSEP) + VTX_GRSEP * (chr == 26); + } else if (chr == 28) { /* Black background */ + page->attrib[pos] = *lastattr & ~VTX_BGMASK; + } else if (chr == 29) { /* Set background */ + page->attrib[pos] = (*lastattr & ~VTX_BGMASK) + ((*lastattr & VTX_COLMASK) << 3); + } else if (chr == 30 || chr == 31) { /* Hold/release graphics */ + page->attrib[pos] = *lastattr; + grhold = (chr == 30); + if (grhold && graphics) + page->chr[pos] = *lastchr; + } else { + assert(0); + } + } + lastchr = page->chr + pos; + if (nextattr) { + lastattr = &next_attrib; + nextattr = 0; + } else { + lastattr = page->attrib + pos; + } + pos++; + } + } + } + return VTXOK; +} diff --git a/src/vtx2ascii-src/vtxdecode.h b/src/vtx2ascii-src/vtxdecode.h new file mode 100644 index 0000000..b56bf75 --- /dev/null +++ b/src/vtx2ascii-src/vtxdecode.h @@ -0,0 +1,45 @@ +#ifndef VTXDECODE_H_INCLUDED +#define VTXDECODE_H_INCLUDED + +/* $Id: vtxdecode.h,v 1.3 1997/03/26 00:17:34 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + */ + + +#include + + +#define VTXOK 0 +#define VTXEINVAL -1 +#define VTXEPARITY -2 + +#define VTX_COLMASK 0x07 /* I rely on the position of the VTX_COLMASK & VTX_BGMASK bits! */ +#define VTX_BGMASK (0x07 << 3) +#define VTX_GRSEP (1 << 7) +#define VTX_HIDDEN (1 << 8) +#define VTX_BOX (1 << 9) +#define VTX_FLASH (1 << 10) +#define VTX_DOUBLE1 (1 << 11) +#define VTX_DOUBLE2 (1 << 12) +#define VTX_INVERT (1 << 13) +#define VTX_DOUBLE (VTX_DOUBLE1 | VTX_DOUBLE2) + + +typedef unsigned char chr_t; +typedef unsigned short attrib_t; +typedef struct { + chr_t chr[VTX_PAGESIZE]; + attrib_t attrib[VTX_PAGESIZE]; + vtx_pageinfo_t info; +} vtxpage_t; + + +extern const chr_t cct2vtx_table[][96]; +extern const char vtx2iso_table[], vtx2iso_lc_table[], vtxiso_worddelim[]; + + +int decode_page(const byte_t *pgbuf, vtxpage_t *page, int y1, int y2); + +#endif /* VTXDECODE_H_INCLUDED */ diff --git a/src/vtx2ascii-src/vtxtools.c b/src/vtx2ascii-src/vtxtools.c new file mode 100644 index 0000000..40c9297 --- /dev/null +++ b/src/vtx2ascii-src/vtxtools.c @@ -0,0 +1,140 @@ +/* + * vtxtools.c: Misceallaneous routines for VideoteXt (parity checking, handling of hexadecimal + * page-numbers) + * + * $Id: vtxtools.c,v 1.1 1996/10/14 21:36:23 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + * + */ + +#include +#include "misc.h" +#include "vtxtools.h" + + +static byte_t parity_table[256]; +static int init_done; + + + +static void +tools_init(void) { + int pos, val, bit; + + for (pos = 0; pos <= 255; pos++) { /* Set up parity_table: If (parity_table[foo] & 0x80), */ + bit = 0; /* foo has odd number of bits set */ + val = pos; + while (val) { /* Count number of set bits in val; see K&R, Exercise 2-9 */ + bit ^= 0x80; + val &= val - 1; + } + parity_table[pos] = bit | 0x7f; + } + /* parity_table is also used for hamming decoding: If (parity_table[foo] & 0x40), foo has + * more than one bit-error and can't be corrected; otherwise the correct(ed) value is + * parity_table[foo] & 0xf + */ + for (pos = 0; pos <= 15; pos++) { + val = ( !(pos & 1) ^ !!(pos & 4) ^ !!(pos & 8)) << 0 | !!(pos & 1) << 1 | + ( !(pos & 1) ^ !!(pos & 2) ^ !!(pos & 8)) << 2 | !!(pos & 2) << 3 | + ( !(pos & 1) ^ !!(pos & 2) ^ !!(pos & 4)) << 4 | !!(pos & 4) << 5 | + (!!(pos & 2) ^ !!(pos & 4) ^ !!(pos & 8)) << 6 | !!(pos & 8) << 7; + for (bit = 0; bit <= 8; bit++) { + parity_table[val ^ ((1 << bit) & 0xff)] &= (0x80 | pos); + } + } + init_done = TRUE; +} + + +/* Check parity of *val (parity bit is bit 7, odd parity) + * Clear bit 7 of *val if parity OK & return TRUE, FALSE otherwise + */ +int +vtx_chkparity(byte_t *val) { + if (!init_done) + tools_init(); + if (parity_table[*val] & 0x80) { + *val &= 0x7f; + return TRUE; + } else return FALSE; +} + + +/* Add odd parity bit to val + */ +byte_t +vtx_mkparity(byte_t val) { + if (!init_done) + tools_init(); + val &= 0x7f; + return val | ((parity_table[val] & 0x80) ? 0 : 128); +} + + +/* Check hamming-encoding of val, return decoded value if OK, -1 otherwise + */ +int +vtx_chkhamming(byte_t val) { + if (!init_done) + tools_init(); + if (parity_table[val] & 0x40) { + return -1; + } else { + return parity_table[val] & 0xf; + } +} + + +/* Increase page-number. Skip over hexadecimal pages + */ +int +inc_vtxpage(int page) { + page++; + if ((page & 0xf) >= 0xa) + page = (page & ~0xf) + 0x10; + if ((page & 0xf0) >= 0xa0) + page = (page & ~0xff) + 0x100; + if (page >= 0x899) + page = 0x100; + return page; +} + + +/* Decrease page-number. Skip over hexadecimal pages + */ +int +dec_vtxpage(int page) { + page--; + if ((page & 0xf) >= 0xa) + page = (page & ~0xf) + 9; + if ((page & 0xf0) >= 0xa0) + page = (page & ~0xff) + 0x99; + if (page < 0x100) + page = 0x899; + return page; +} + + +int +vtx_hex2dec(int pgnum) { + return (pgnum / 0x100) * 100 + ((pgnum / 0x10) % 0x10) * 10 + (pgnum % 0x10); +} + + +int +vtx_dec2hex(int pgnum) { + return (pgnum / 100) * 0x100 + ((pgnum / 10) % 10) * 0x10 + (pgnum % 10); +} + + +int +vtx_chkpgnum(int pgnum, int hex_ok) { + if (hex_ok) { + return (pgnum >= 0x100 && pgnum <= 0x8ff); + } else { + return (pgnum >= 0x100 && pgnum <= 0x899 && (pgnum & 0xff) <= 0x99 && (pgnum & 0xf) <= 9); + } +} diff --git a/src/vtx2ascii-src/vtxtools.h b/src/vtx2ascii-src/vtxtools.h new file mode 100644 index 0000000..b819d84 --- /dev/null +++ b/src/vtx2ascii-src/vtxtools.h @@ -0,0 +1,23 @@ +#ifndef VTXTOOLS_H_INCLUDED +#define VTXTOOLS_H_INCLUDED + +/* $Id: vtxtools.h,v 1.1 1996/10/14 21:36:25 mb Exp mb $ + * + * Copyright (c) 1994-96 Martin Buck + * Read COPYING for more information + */ + + +#include + + +int vtx_chkparity(byte_t *val); +byte_t vtx_mkparity(byte_t val); +int vtx_chkhamming(byte_t val); +int inc_vtxpage(int page); +int dec_vtxpage(int page); +int vtx_hex2dec(int pgnum); +int vtx_dec2hex(int pgnum); +int vtx_chkpgnum(int pgnum, int hex_ok); + +#endif /* VTXTOOLS_H_INCLUDED */ diff --git a/ttxd.service b/ttxd.service new file mode 100644 index 0000000..f0133b8 --- /dev/null +++ b/ttxd.service @@ -0,0 +1,12 @@ +[Unit] +Description=Teletext Server (ttxd) +After=network.target + +[Service] +ExecStart=/opt/ttxd/serv.sh +ExecStop=/usr/bin/killall dvbtext tzap thttpd +KillMode=process +Type=forking + +[Install] +WantedBy=default.target -- 2.39.3