#!/bin/bash
# Configuration options
STORAGE_PREFIX="/storage/md0"
HEADER="/data/sites/slackware.uk/html/search_header.html"
FOOTER="/data/sites/slackware.uk/html/search_footer.html"
LOCATEDB="/tmp/mirrors.db"
LIMIT=1000
MAX_CONCURRENT=5
# Extglob is required.
shopt -s extglob
# Output an error in processing.
die() {
echo "
Error: $1
"
exit 1
}
# A content type is required for CGI scripts.
echo -ne "Content-type: text/html\r\n\r\n"
# Include the header in the output.
# Note: The header cannot include PHP scripting.
cat "$HEADER"
# Limit the number of concurrent searches to avoid DoS.
if (( $(lsof -t "$LOCATEDB" | wc -l) > MAX_CONCURRENT - 1 )); then
die "Too many concurrent searches - please try your search again in a few moments."
else
exec 9<"$LOCATEDB" && flock -s -E 10 -w 2 9 || die "Too many concurrent searches - please try your search again in a few moments."
fi
while read -r -d '&'; do
# If the read returned an empty string, skip.
[[ -z "$REPLY" ]] && continue
# Extract the key and value to temporary variables.
KEY="${REPLY%%=*}"
VALUE="${REPLY##*=}"
# Check the key is valid as a variable name.
[[ ! "$KEY" =~ ^[[:alpha:]]+[[:digit:]_]*[[:alnum:]_]*$ ]] && die "Invalid key - please try your search again."
# Remove spaces from beginning and end of value.
: "${VALUE/#+(+)}"
: "${_/%+(+)}"
# Squash multiple spaces in value and add *s.
: "${_//+(+)/+}"
# Convert values from %-encoded form.
: "${_//%/\\x}"
# Define the variable from the key name.
declare $KEY="$(echo -e "${_//+/ }")"
done <<<"${QUERY_STRING,,}&"
# Take a copy of q before it's modified, for the heading.
Q_COPY="${q:-(empty)}"
# Adjust 'q' for the locate command by wrapping search elements in *s.
: "*${q// /* *}*"
q="${_//\/*/*}"
# HTML boilerplate.
cat <
EOF
I=1
COUNT=0
while read -r; do
# Only show 1000 items to prevent long load times.
(( I == LIMIT + 1 )) && break
# Remove paths we don't want the user to see.
[[ "${REPLY/$STORAGE_PREFIX}" =~ ^/\.sandbox.* ]] && continue
[[ "${REPLY/$STORAGE_PREFIX}" =~ ^/\.lftp.* ]] && continue
[[ "${REPLY/$STORAGE_PREFIX}" =~ ^/dead\.letter ]] && continue
[[ "${REPLY/$STORAGE_PREFIX}" =~ .*\.rsync-tmp.* ]] && continue
# List the item.
echo " • ${REPLY/$STORAGE_PREFIX} "
(( I++ ))
(( COUNT++ ))
done < <(locate -A -d "$LOCATEDB" -i -l "$(( LIMIT * 2 ))" "$STORAGE_PREFIX/${p##/}" $q | sort)
# If there's no results, tell the user.
if (( COUNT == 0 )); then
echo " No results - try to widen your search."
elif (( COUNT == LIMIT )); then
echo " Maximum $LIMIT items shown - try to refine your search."
else
echo " $COUNT items found."
fi
# HTML boilerplate.
cat <
|
EOF
# Include footer.
cat "$FOOTER"