serv/serv.sh

321 lines
6.6 KiB
Bash
Raw Normal View History

2021-07-11 10:20:48 +10:00
#!/bin/bash
function lookup() { # lookup where_var res_var what to lookup ...
local all what found rv localres where_var res_var
where_var="$1" ; shift
res_var="$1" ; shift
all="${*}"
what=${all// /|}
found=""
localres=$(egrep -i "$what" $SRVFILE_CUSTOM)
if [[ ! -z $localres ]]; then
found="custom"
else
localres=$(egrep -i "$what" $SRVFILE_BASE)
[[ ! -z $localres ]] && found="system"
fi
eval "$where_var=${found}"
eval "$res_var='${localres}'"
if [[ -z $found ]]; then
rv=1
else
rv=0
fi
return $rv
echo "$found"
}
function usage() {
echo "usage: $0 [OPTIONS] command [command_args]"
echo
echo "Manage custom /etc/services entries."
echo
echo " Valid commands are: $VALIDMODES"
echo
echo " -f Force removal of service even if multiple match."
echo " -w Update system services file ($SRVFILE_ACTIVE)"
echo " -y Same as -w"
echo
}
function getalt() {
local newmode
newmode="$1"
case $1 in
a)
newmode="add";
;;
q)
newmode="query";
;;
rm)
newmode="del";
;;
esac
echo "$newmode"
}
function makeboth() {
local n p both
n="$1"
p="$2"
both="$n"
if [[ ! -z $p ]]; then
if [[ ! -z $n ]]; then
both="$both ("
fi
both="$both$p"
if [[ ! -z $n ]]; then
both="$both)"
fi
fi
echo "$both"
}
function stageforsync() {
cp -fp "$SRVFILE_BASE" "$SRVFILE_STAGE"
echo >> "$SRVFILE_STAGE"
echo "# custom services from serv.sh" >> "$SRVFILE_STAGE"
cat "$SRVFILE_CUSTOM" >> "$SRVFILE_STAGE"
}
function synctoactive() {
local perm dres
stageforsync
dres=$(diff "$SRVFILE_ACTIVE" "$SRVFILE_STAGE")
echo
if [[ $DOIT -eq 1 ]]; then
perm=$(stat -f "%p" "$SRVFILE_ACTIVE")
if [[ $UID -ne 0 && $EUID -ne 0 ]]; then
echo "(using sudo - you may be prompted for your password)"
sudo cp -fp "$SRVFILE_ACTIVE" "$SRVFILE_ACTIVE.orig"
sudo cp -fp "$SRVFILE_STAGE" "$SRVFILE_ACTIVE"
sudo chmod $perm "$SRVFILE_ACTIVE"
else
cp -fp "$SRVFILE_ACTIVE" "$SRVFILE_ACTIVE.orig"
cp -fp "$SRVFILE_STAGE" "$SRVFILE_ACTIVE"
chmod $perm "$SRVFILE_ACTIVE"
fi
if [[ -z $dres ]]; then
echo "No changes required to $SRVFILE_ACTIVE."
else
echo "$SRVFILE_ACTIVE updated:"
echo "$dres" | sed -e 's/^/ /'
fi
else
echo "NOTE: $SRVFILE_ACTIVE not touched - use -w to update it."
echo "The following changes were NOT made:"
if [[ -z $dres ]]; then
echo " (none)"
else
echo "$dres" | sed -e 's/^/ /'
fi
fi
}
# Handle args
VALIDPROTOS="tcp udp"
VALIDMODES="diff sync init add del query cat"
MODE=""
SRVFILE_ACTIVE="/etc/services"
SRVDIR="${HOME}/.serv"
SRVFILE_BASE="${SRVDIR}/base"
SRVFILE_CUSTOM="${SRVDIR}/custom"
SRVFILE_STAGE="${SRVDIR}/stage"
PROTOFILE=/etc/protocols
FORCE=0
DOIT=0
ARGS="fhwy"
while getopts "$ARGS" i; do
case "$i" in
f)
FORCE=1
;;
h)
usage;
exit 1
;;
w)
DOIT=1;
;;
y)
DOIT=1;
;;
*)
echo "ERROR: invalid argument: $i";
usage;
;;
esac
done
shift $((OPTIND - 1))
if [[ $# -eq 0 ]]; then
echo "Error - no mode provided."
usage
exit 1
fi
MODE="$1"
shift 1
MODE=$(getalt $MODE)
if [[ $VALIDMODES != *$MODE* ]]; then
echo "Error - invalid mode '$MODE'"
echo "Valid modes are: $VALIDMODES"
exit 1
fi
if [[ $MODE == "cat" ]]; then
echo "Current custom services (from $SRVFILE_CUSTOM):"
cat "$SRVFILE_CUSTOM" | sed -e 's/^/ /'
exit 0
elif [[ $MODE == "diff" ]]; then
stageforsync
dres=$(diff "$SRVFILE_ACTIVE" "$SRVFILE_STAGE")
echo "Changes to be synced into $SRVFILE_ACTIVE:"
if [[ -z $dres ]]; then
echo " (none)"
else
echo "$dres" | sed -e 's/^/ /'
fi
exit 0
elif [[ $MODE == "sync" ]]; then
# just update /etc/services
synctoactive
exit 0
elif [[ $MODE == "init" ]]; then
wantargs=0
elif [[ $MODE == "add" ]]; then
wantargs=2
else
wantargs=1
fi
if [[ $# -lt $wantargs ]]; then
echo "Bad arguments - want $wantargs, got $#"
echo
usage
exit 1
fi
name="$1"
protoport="$2"
if [[ -z $protoport ]]; then
proto=""
port=""
else
if [[ $protoport != */* ]]; then
echo "Error - bad service specification '$protoport'"
echo "Must use the format: port/protocol"
exit 1
fi
proto="${protoport#*/}"
port="${protoport%/*}"
re='^[0-9]+$'
if [[ ! $port =~ $re ]]; then
echo "Error - port '$port' is not a number."
echo "Must use the format: port/protocol"
exit 1
fi
if [[ $port -lt 0 || $port -gt 65535 ]]; then
echo "Error - port '$port' must be in the range 0-65535."
exit 1
fi
if [[ $VALIDPROTOS != *$proto* ]]; then
echo "Error - invalid protocol '$proto'."
echo "Valid protocols are: $VALIDPROTOS"
exit 1
fi
shift 2
comment="$*"
fi
both=$(makeboth $name $protoport)
if [[ $MODE == "init" ]]; then
if [[ -d $SRVDIR ]]; then
echo "error -i $SRVDIR already exists."
exit 1
fi
mkdir -p "$SRVDIR"
cp -p "$SRVFILE_ACTIVE" "$SRVFILE_BASE"
cp /dev/null "$SRVFILE_CUSTOM"
echo "Initialisation of $SRVDIR complete."
exit 0
elif [[ ! -d $SRVDIR ]]; then
echo "Error - $SRVDIR is missing."
echo "Use -i to initialise it."
exit 1
fi
if [[ $MODE == "query" ]]; then
lookup whichfile res $name $protoport
if [[ ! -z $whichfile ]]; then
echo "Found in $whichfile services file:"
echo "$res" | sed -e 's/^/ /'
exit 0
else
echo "'$both' not found."
exit 1
fi
elif [[ $MODE == "add" ]]; then
lookup whichfile res $name $protoport
if [[ ! -z $whichfile ]]; then
echo "Error - this already exists in $whichfile services file:"
echo "$res" | sed -e 's/^/ /'
exit 1
fi
if [[ ${#name} -gt 15 ]]; then
echo "Error - service name '$name' exceeds 15 characters."
exit 1
fi
if [[ -z $comment ]]; then
printf "%-16s%s\n" "$name" "$protoport" >> $SRVFILE_CUSTOM
else
printf "%-16s%s # %s\n" "$name" "$protoport" "$comment" >> $SRVFILE_CUSTOM
fi
echo "Added '$name' ($protoport) to custom services file."
synctoactive
elif [[ $MODE == "del" ]]; then
lookup whichfile res $name $protoport
if [[ $whichfile != "custom" ]]; then
echo "Error - can't find service '$both' in custom file."
exit 1
fi
re="$name"
if [[ ! -z $protoport ]]; then
if [[ ! -z $re ]]; then
re="$re|"
fi
re="$re${protoport}"
fi
re="${re/\//\\\/}" # escape the slash
count=$(egrep -c "$re" $SRVFILE_CUSTOM)
[[ $count -eq 1 ]] && ess="" || ess="s"
if [[ $count -gt 1 && $FORCE -ne 1 ]]; then
echo "Error: '$both' matches multiple lines for removal, use -f to confirm:"
echo "$res" | sed -e 's/^/ /'
exit 1
fi
sed -ibak "/$re/d" $SRVFILE_CUSTOM
sedrv=$?
if [[ $sedrv -eq 0 ]]; then
echo "Removed '$both' from custom services file ($count line$ess)."
rv=0
else
echo "Error failed to remove '$both' from custom services file using sed."
rv=1
fi
synctoactive
exit $rv
fi
# TODO: sync to real serviceafile
exit 0