321 lines
6.6 KiB
Bash
Executable File
321 lines
6.6 KiB
Bash
Executable File
#!/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
|