update: function update { ... }, color logging, update_serial
#!/bin/bash
# vim: set ft=sh :
set -ue
ROOT=$(pwd)
BIN=bin
PROCESS_ZONE=$BIN/process-zone
EXPAND_ZONE=$BIN/expand-zone
UPDATE_SERIAL=$BIN/update-serial
SETTINGS=settings
ZONES=zones
SERIALS=serials
PROCESS_ARGS='--input-charset latin-1'
FORWARD_MX=mail
REVERSE_ZONE=194.197.235
REVERSE_DOMAIN=paivola.fi
## options
IS_TTY=
UPDATE_FORCE=
SERIAL_NOUPDATE=
function help_args {
local prog=$1
cat <<END
Usage: $prog [options]
-h display this help text
-F force-updates without checking src mtime
-S do not update serial
END
}
function parse_args {
OPTIND=1
while getopts 'hFS' opt "$@"; do
case $opt in
h)
help_args $1
exit 0
;;
F) UPDATE_FORCE=y ;;
S) SERIAL_NOUPDATE=y ;;
?)
die
;;
esac
done
}
## lib
function log_msg {
echo "$*" >&2
}
function log_color {
local code=$1; shift
if [ $IS_TTY ]; then
echo $'\e[0;'${code}'m'"$*"$'\e[00m' >&2
else
echo "$*" >&2
fi
}
function log_error {
log_color 31 "$*"
}
function log {
log_msg "$*"
}
function log_info {
log_color 36 " $*"
}
function log_debug {
log_color 32 " $*"
}
function log_cmd {
log_color 35 " \$ $*"
}
function die {
log_error "$*"
exit 1
}
function cmd {
log_cmd "$@"
"$@" || die "Failed"
}
function run_cmd {
local msg=$1; shift
log_info "$msg... "
cmd "$@"
}
function indent () {
"$@" | (
while read line; do
echo " $line"
done
) || exit $?
}
## test
[ -d $SETTINGS ] || die "Missing settings: $SETTINGS"
[ -d $SERIALS ] || die "Missing serials: $SERIALS"
[ -d $ZONES ] || die "Missing zones: $ZONES"
## functions
function update {
local dst=$1
local src=$2
local tmp=$dst.new
shift 2
if [ -z $src ] || [ $UPDATE_FORCE ] || [ $dst -ot $src ]; then
log_debug "update: $dst <- $src"
cmd "$@" $src > $tmp
# compare
if [ -e $dst ]; then
# terse
indent diff --unified=1 $dst $tmp
fi
# overwrite
mv $tmp $dst
else
log_debug "$dst <- $src: up-to-date"
fi
}
## bin wrappers
function update_serial {
cmd $UPDATE_SERIAL $*
}
function expand_zone {
local output=$1; shift
local src=$1; shift
update $output $src $EXPAND_ZONE "$@"
}
function process_zone {
local output=$1; shift
local src=$1; shift
update $output $src $PROCESS_ZONE $PROCESS_ARGS "$@"
}
## actions
function copy_zone_part {
local zone=$1
local part=$2
local name=$zone.zone.$part
log_info "Copying zone $zone/$part: zones/$name"
update $ZONES/$name $SETTINGS/$name cat
}
function update_zone {
local zone=$1
local name=$zone.zone
log_info "Generating $zone zone headers: zones/$name"
expand_zone $ZONES/$name $SETTINGS/$zone.zone \
--serial $SERIALS/$zone.serial \
--expand zones=$ROOT/$ZONES
}
function update_zone_view {
local zone=$1
local view=$2
local name=$view/$zone.zone
log_info "Generating $zone:$view zone headers: zones/$name"
expand_zone $ZONES/$name $SETTINGS/$zone.zone \
--serial $SERIALS/$zone.serial \
--expand zones=$ROOT/$ZONES \
--expand view=$view
}
function main {
# test tty
[ -t 1 ] && IS_TTY=y
parse_args "$@"
if [ $SERIAL_NOUPDATE ]; then
log_debug "skipping serial-update"
else
log "Updating serials..."
update_serial $SERIALS/paivola.serial
update_serial $SERIALS/paivola-reverse.serial
fi
log "Generating host zones..."
process_zone $ZONES/external/paivola.zone.hosts $SETTINGS/paivola.txt --forward-zone
process_zone $ZONES/internal/paivola.zone.hosts $SETTINGS/paivola.txt --forward-zone --forward-txt --forward-mx $FORWARD_MX
process_zone $ZONES/paivola-reverse.zone.hosts $SETTINGS/paivola.txt --reverse-zone $REVERSE_ZONE --reverse-domain $REVERSE_DOMAIN
log "Copying zone parts..."
copy_zone_part paivola auto
copy_zone_part paivola services
copy_zone_part paivola internal
copy_zone_part paivola external
log "Updating zones..."
update_zone paivola-reverse
update_zone_view paivola internal
update_zone_view paivola external
}
main "$@"