#! /bin/bash
# -*- mode: sh; sh-basic-offset: 4; indent-tabs-mode: nil; -*-
#
# SVN version: $Id: metche 210 2009-12-01 11:21:51Z intrigeri $
# $URL: https://dev.potager.org/svn/metche/upstream/trunk/metche $
#
# metche: reducing root bus factor
# Copyright (C) 2004-2006 boum.org collective - property is theft !
#
# 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.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
set -e
shopt -s nullglob
###
### Auxiliary functions
###
display_usage() {
( echo "Usage:"
echo " `basename $0` [-h VSERVER] list"
echo " `basename $0` [-h VSERVER] report" \
"[{stable|testing|unstable}-YYYYMMDDHHMM]"
echo " `basename $0` [-h VSERVER] stabilize [testing-YYYYMMDDHHMM]"
echo ""
echo " With -h, the VServer VSERVER is operated on instead of the host system."
echo ""
echo "Non-interactive usage:"
echo " `basename $0` cron"
echo ""
) >&2
}
fatal() {
echo -e "Fatal: $@" >&2
exit 2
}
warning() {
echo -e "Warning: $@" >&2
}
debug() {
[ "$DEBUG" != yes ] || echo -e "Debug: $@" >&2
}
executable_not_found() {
local executable="$1"
local software="$2"
local dependant_option="$3"
local solution_option="$4"
if [ -z "$solution_option" ]; then
fatal "$executable not found on `current_system`." \
"Please install $software or turn $dependant_option off."
else
fatal "$executable not found on `current_system`." \
"Please install $software, customize $solution_option" \
"or turn $dependant_option off."
fi
}
email() {
debug "* email $@ to $EMAIL_ADDRESS"
local subject="`current_system` - $_MAIL_SUBJECT : $1"
if [ $ENCRYPT_EMAIL = "yes" ]; then
LC_ALL="$LOCALE" gpg --batch --armor --encrypt \
--recipient "$EMAIL_ADDRESS" |
LC_ALL="$LOCALE" mutt -s "$subject" "$EMAIL_ADDRESS"
else
LC_ALL="$LOCALE" mutt -s "$subject" "$EMAIL_ADDRESS"
fi
}
current_system() {
$VSERVER_EXEC_PREFIX hostname -f
}
###
### Configuration
###
DEBUG="yes"
WATCHED_DIR="/etc"
BACKUP_DIR="/var/lib/metche"
# if set, activate single changelog mode
#CHANGELOG_FILE="/root/Changelog"
# if set, activate multiple changelogs mode
#CHANGELOG_DIR="/root/changelogs"
DO_PACKAGES="no"
DO_DETAILS="no"
TESTING_TIME="60"
STABLE_TIME="3"
EMAIL_ADDRESS="root@`hostname -f`"
ENCRYPT_EMAIL="no"
SEND_STABLE_REPORTS="yes"
EXCLUDES="*.swp #* *~ *.gpg *.key ifstate adjtime ld.so.cache shadow* \
.cache .gnupg blkid.tab* aumixrc net.enable mtab backup.d \
vdirbase run.rev vdir run.rev \
prng_exch smtp_scache.pag smtpd_scache.pag \
smtp_scache.dir smtpd_scache.dir local.sh \
ssh_host_dsa_key* ssh_host_rsa_key*"
LOCALE="C"
VSNAMES=""
VSERVERINFO=/usr/sbin/vserver-info
VSERVER=/usr/sbin/vserver
_MAIL_SUBJECT="changes report"
_NO_DEBIAN_PACKAGES_CHANGE="No change in Debian packages state."
_NO_CHANGE="No change."
MAIN_HEADER="
c h a n g e s r e p o r t
---------------------------
"
CHANGELOGS_HEADER="
Changelogs
==========
"
FILES_HEADER="
Changed files
=============
"
DEBIAN_PACKAGES_HEADER="
Changes in Debian packages
==========================
"
FILES_DETAILS_HEADER="
Details for changed files
=========================
"
if [ "$1" = "-h" ]; then
VSNAME="$2"
CMD="$3"
MILESTONE="$4"
else
CMD="$1"
MILESTONE="$2"
fi
if [ -f /etc/metche.conf ]; then
. /etc/metche.conf
else
display_usage
fatal "Config file not found."
fi
PATH="/bin:/usr/bin"
unset LC_ALL
unset LC_CTYPE
unset LANGUAGE
unset LANG
umask 077
# Manage deprecated configuration files and options
test ! -d /etc/metche || fatal "An old configuration directory (/etc/metche/)" \
"was found, please upgrade your configuration."
test -z "$TAR_OPTS" || fatal "TAR_OPTS is deprecated, use EXCLUDES instead."
# Backup various configuration values: these non-underscored variable
# names will be re-initialized in context_config() and re-used everywhere.
_WATCHED_DIR="$WATCHED_DIR"
_BACKUP_DIR="$BACKUP_DIR"
_CHANGELOG_DIR="$CHANGELOG_DIR"
_CHANGELOG_FILE="$CHANGELOG_FILE"
_DO_PACKAGES="$DO_PACKAGES"
_EMAIL_ADDRESS="$EMAIL_ADDRESS"
if [ -n "$VSNAMES" ]; then
# check VSERVERINFO and VSERVER availability
test -x "$VSERVERINFO" || \
executable_not_found "vserver-info" "util-vserver" "VSNAMES" "VSERVERINFO"
test -x "$VSERVER" || \
executable_not_found "vserver" "util-vserver" "VSNAMES" "VSERVER"
# check VROOTDIR availability
test -n "$VROOTDIR" || \
VROOTDIR="`$VSERVERINFO info SYSINFO \
| grep '^ *vserver-Rootdir' | awk '{print $2}'`"
test -n "$VROOTDIR" || \
fatal "VSNAMES is not empty, but VROOTDIR could not be guessed." \
"Please set VROOTDIR in /etc/metche.conf."
test -d "$VROOTDIR" || \
fatal "VSNAMES is not empty, but VROOTDIR ($VROOTDIR) does not exist." \
"Please set VROOTDIR in /etc/metche.conf."
# expand VSNAMES if it is set to "all"
if [ "$VSNAMES" = all ]; then
VSNAMES=`ls $VROOTDIR | grep -E -v "lost\+found|ARCHIVES" | tr "\n" " "`
if [ -z "$VSNAMES" ]; then
warning "VSNAMES is set to \"all\", but no VServer could be found" \
"in VROOTDIR ($VROOTDIR)."
fi
fi
fi
if [ "$ENCRYPT_EMAIL" = "yes" ]; then
which gpg > /dev/null ||
executable_not_found "gpg" "GnuPG" "ENCRYPT_EMAIL"
fi
DATE=`date "+%Y%m%d%H%M"`
# How to use $TAR_OPTS:
# - $TAR_OPTS should be used unquoted
# - 'set -o noglob' has to be run before any $TAR_OPTS use
# - 'set +o noglob' has to be run after any $TAR_OPTS use
TAR_OPTS=""
set -o noglob
for pattern in $EXCLUDES; do
TAR_OPTS="$TAR_OPTS --exclude=$pattern"
done
set +o noglob
# How to use $FIND_OPTS:
# - $FIND_OPTS should appear unquoted between:
# . the (optional) target files and directories
# . the (compulsory) action, such as -print or -exec
# - 'set -o noglob' has to be run before any $FIND_OPTS use
# - 'set +o noglob' has to be run after any $FIND_OPTS use
FIND_OPTS=""
set -o noglob
# DO NOT fix me: the final -or at the end of $FIND_OPTS is really needed
for pattern in $EXCLUDES; do
FIND_OPTS="$FIND_OPTS -path */$pattern -prune -or"
done
set +o noglob
###
### A few functions to do the real work
###
# Check and mangle the context-dependant configuration variables,
# i.e. the parameters specific to the host system or to a given VServer.
# If $1 is empty, operate on the host system.
# Else, operate on a VServer and return with exit-code:
# - 2 if $1 is not an existing VServer
# - 3 if $1 is not a VServer listed in VSNAMES
# - 4 if $1 is not a running VServer
# Anyway, return with exit-code:
# - 5 if the GnuPG public key can not be found
context_config() {
local vsname="$1"
local res
debug "-------- Operating on" \
"`if [ -z $vsname ]; then echo 'the host system'; else echo VServer $vsname; fi`"
debug "* context_config"
#
# Variables & VServer
#
if [ -z "$vsname" ]; then
WATCHED_DIR="$_WATCHED_DIR"
BACKUP_DIR="$_BACKUP_DIR"
VSERVER_EXEC_PREFIX=""
EMAIL_ADDRESS="$_EMAIL_ADDRESS"
else
WATCHED_DIR="$VROOTDIR/$vsname/$_WATCHED_DIR"
BACKUP_DIR="$_BACKUP_DIR/$vsname"
VSERVER_EXEC_PREFIX="$VSERVER $vsname exec"
EMAIL_ADDRESS="root@`current_system`"
# does the current VServer exist ?
if [ ! -d "$VROOTDIR/$vsname" ]; then
warning " VServer $vsname does not exist (error 2)."
return 2
fi
# is the current VServer listed in VSNAMES ?
local found="no";
for i in $VSNAMES; do
if [ "$vsname" = "$i" ]; then
found=yes
break
fi
done
if [ $found = no ]; then
warning " VServer $vsname is not listed in VSNAMES (error 3)."
return 3
fi
# is the current VServer running ?
res=""
$VSERVERINFO -q "$vsname" RUNNING || res=failed
if [ "$res" = failed ]; then
warning " VServer $vsname is not running (error 4)."
return 4
fi
fi
# E-mail encryption
if [ $ENCRYPT_EMAIL = "yes" ]; then
gpg --batch --list-public-keys $EMAIL_ADDRESS >/dev/null 2>&1
res=$?
if [ $res -ne 0 ]; then
warning " GnuPG public key for $EMAIL_ADDRESS not found."
return 5
fi
fi
#
# Files and directories
#
# Check the existence of WATCHED_DIR
test -d "$WATCHED_DIR" || \
fatal "$WATCHED_DIR directory (built from WATCHED_DIR) does not exist."
# Initialize WATCHED_PARENT
WATCHED_PARENT=`dirname $WATCHED_DIR`
if [ "$WATCHED_PARENT" != '/' ]; then
WATCHED_PARENT="$WATCHED_PARENT/"
fi
# Check the existence of the resulting BACKUP_DIR, creating it if needed.
if [ ! -d "$BACKUP_DIR" ]; then
debug " Creating $BACKUP_DIR directory for `current_system`."
if mkdir -p "$BACKUP_DIR"; then
debug " Successfully created $BACKUP_DIR directory."
else
fatal " Failed to create $BACKUP_DIR directory."
fi
fi
#
# Modules enabling/disabling
#
# DO_CHANGELOGS
DO_CHANGELOGS="no"
if [ -n "$_CHANGELOG_DIR" ]; then
if [ -z "$vsname" ]; then
CHANGELOG_DIR="$_CHANGELOG_DIR"
else
CHANGELOG_DIR="$VROOTDIR/$vsname$_CHANGELOG_DIR"
fi
if [ -d "$CHANGELOG_DIR" ]; then
DO_CHANGELOGS="dir"
else
warning " The directory $CHANGELOG_DIR (built from CHANGELOG_DIR)" \
" does not exist. Changelogs file monitoring thereferore" \
" cannot be performed this time for `current_system`."
fi
elif [ -n "$CHANGELOG_FILE" ]; then
if [ -z "$vsname" ]; then
CHANGELOG_FILE="$_CHANGELOG_FILE"
else
CHANGELOG_FILE="$VROOTDIR/$vsname$_CHANGELOG_FILE"
fi
if [ -f "$CHANGELOG_FILE" ]; then
DO_CHANGELOGS="file"
else
warning " The file $CHANGELOG_FILE (built from CHANGELOG_FILE)"
warning " does not exist. Changelog file monitoring thereferore"
warning " cannot be performed this time for `current_system`."
fi
fi
# DO_PACKAGES
DO_PACKAGES="$_DO_PACKAGES"
if [ "$DO_PACKAGES" = "yes" ]; then
$VSERVER_EXEC_PREFIX which apt-show-versions > /dev/null
res=$?
if [ $res -ne 0 ]; then
warning " apt-show-versions not found on `current_system`."
warning " Please install it or turn DO_PACKAGES off."
warning " DO_PACKAGES therefore cannot be performed this time"
warning " for `current_system`."
DO_PACKAGES=no
fi
fi
#
# Final steps to get a coherent initial status
#
# Make sure we've got at least one testing and one stable
milestone_exists testing-latest || save_state "testing"
milestone_exists stable-latest || stabilize_state "testing-latest"
}
# Returns 0 if, and only if, specified milestone exists.
milestone_exists() {
local milestone="$1"
if [ -f "${BACKUP_DIR}/${milestone}.tar.bz2" -o \
-L "${BACKUP_DIR}/${milestone}.tar.bz2" ]; then
return 0
else
return 1
fi
}
# Echoes the given milestone's version (i.e. "stable", "testing", "unstable")
# if it has a valid version, else "none".
# The given milestone can be inexistant.
milestone_version() {
local milestone="$1"
local version="`echo $milestone | sed 's/-.*$//'`"
case $version in
stable|testing|unstable)
echo $version;;
*)
echo "none";;
esac
}
# Echoes given milestone's date.
# Symlinks (e.g.: *-latest) are dereferenced if needed.
# The given milestone can be inexistant.
milestone_date() {
local milestone="$1"
if [ -L "${BACKUP_DIR}/${milestone}.tar.bz2" ]; then
milestone="`readlink ${BACKUP_DIR}/${milestone}.tar.bz2`"
fi
echo `basename $milestone` | sed 's/.*-//' | sed 's/\..*$//'
}
# Returns 0 if, and only if, the given milestone ($1) is the latest one
# of its type.
# The given milestone can be inexistant.
is_latest() {
local file milestone ref_milestone ref_date ref_version
ref_milestone="$1"
ref_date="`milestone_date $ref_milestone`"
ref_version="`milestone_version $ref_milestone`"
for file in "${BACKUP_DIR}/${ref_version}-"*.tar.bz2; do
milestone=`basename $file | sed 's/\.tar\.bz2$//'`
if [ "`milestone_date $milestone`" -gt "$ref_date" ]; then
return 1
fi
done
return 0
}
# This will save an archive of the watched directory with the given prefix
save_files() {
debug " - save_files $@"
set -o noglob
tar jcf "$BACKUP_DIR/$1-$DATE".tar.bz2 \
-C "$WATCHED_PARENT" $TAR_OPTS `basename "$WATCHED_DIR"`
set +o noglob
ln -sf "$1-$DATE".tar.bz2 "$BACKUP_DIR/$1"-latest.tar.bz2
}
# This will save packages list with the given prefix
save_packages() {
debug " - save_packages $@"
$VSERVER_EXEC_PREFIX apt-show-versions -i
$VSERVER_EXEC_PREFIX apt-show-versions |
sort > "$BACKUP_DIR/$1-$DATE".packages
ln -sf "$1-$DATE".packages "$BACKUP_DIR/$1"-latest.packages
}
# This will save Changelogs with the given prefix
save_changelogs() {
debug " - save_changelogs $@"
local changelog domain file
if [ "$DO_CHANGELOGS" = "dir" ]; then
for file in "$CHANGELOG_DIR"/*/Changelog; do
changelog="${file##$CHANGELOG_DIR/}"
domain="${changelog%%/Changelog}"
cat "$file" > "$BACKUP_DIR/$1-$DATE.$domain.Changelog"
ln -sf "$1-$DATE.$domain.Changelog" \
"$BACKUP_DIR/$1-latest.$domain.Changelog"
done
elif [ "$DO_CHANGELOGS" = "file" ]; then
cat "$CHANGELOG_FILE" > "$BACKUP_DIR/$1-$DATE.Changelog"
ln -sf "$1-$DATE.Changelog" "$BACKUP_DIR/$1-latest.Changelog"
fi
}
# Save whatever reflect the current state with the given prefix
save_state() {
debug "* save_state $@"
save_files "$1"
[ $DO_PACKAGES = "no" ] || save_packages "$1"
[ $DO_CHANGELOGS = "no" ] || save_changelogs "$1"
}
# Report changes against given version to standard output
report_changes() {
debug "* report_changes $@"
local tmp tmpdir changelog domain diff tar_diff diff_diff
local files old new tmp_packages file
# File to store results
tmp=`mktemp -q`
# We need to diff against given version, so extract it
tmpdir=`mktemp -d -q`
tar jxf "$BACKUP_DIR/$1".tar.bz2 -C "$tmpdir"
echo "$MAIN_HEADER" >> "$tmp"
if [ $DO_CHANGELOGS = "dir" ]; then
echo "$CHANGELOGS_HEADER" >> "$tmp"
for file in "$CHANGELOG_DIR"/*/Changelog; do
changelog="${file##$CHANGELOG_DIR/}"
domain="${changelog%%/Changelog}"
diff=`LC_ALL=$LOCALE \
diff -wEbBN "$BACKUP_DIR/$1.$domain.Changelog" \
"$file"` ||
# diff returns false when files differ
(echo "$domain:" ; echo "$diff" |
grep -v '^[0-9-]\|^\\') >> "$tmp"
done
fi
if [ $DO_CHANGELOGS = "file" ]; then
echo "$CHANGELOGS_HEADER" >> "$tmp"
diff=`LC_ALL=$LOCALE \
diff -wEbBN "$BACKUP_DIR/$1.Changelog" "$CHANGELOG_FILE"` ||
# diff returns false when files differ
(echo "$diff" | grep -v '^[0-9-]\|^\\') >> "$tmp"
fi
echo "$FILES_HEADER" >> "$tmp"
# Find differences with tar
set -o noglob
tar_diff=$(tar jdf "$BACKUP_DIR/$1".tar.bz2 \
-C "$WATCHED_PARENT" $TAR_OPTS 2>&1 |
# transform:
# etc/issue: Gid differs -> etc/issue
# tar: etc/irssi.conf: ... -> etc/irssi.conf
sed -e 's/\(tar: \)\?\([^:]*\):.*/\2/')
# Get new files
diff_diff=$(diff -qr $TAR_OPTS "$tmpdir"/`basename "$WATCHED_DIR"` \
"$WATCHED_DIR" 2>/dev/null |
# Only in test/etc: issue -> test/etc/issue
sed -n -e "s,^Only in $WATCHED_PARENT\([^:]*\): \(.*\),\1/\2,p")
files="`echo "$tar_diff$diff_diff" | sort -u`"
set +o noglob
if [ -z "$files" ]; then
echo "$_NO_CHANGE" >> "$tmp"
else
for file in $files; do
old="$tmpdir"/"$file"
new="$WATCHED_PARENT$file"
if [ -e "$old" -a -e "$new" ]; then
echo -n '< '
ls -ld "$old" | sed -e "s;$tmpdir/;;"
echo -n '> '
ls -ld "$new" | sed -e "s;$WATCHED_PARENT;;"
elif [ -e "$old" ]; then
echo -n '- '
ls -ld "$old" | sed -e "s;$tmpdir/;;"
elif [ -e "$new" ]; then
echo -n '+ '
ls -ld "$new" | sed -e "s;$WATCHED_PARENT;;"
fi
done >> "$tmp"
fi
if [ "$DO_PACKAGES" = "yes" ]; then
echo "$DEBIAN_PACKAGES_HEADER" >> "$tmp"
tmp_packages=`mktemp -q`
$VSERVER_EXEC_PREFIX apt-show-versions -i
$VSERVER_EXEC_PREFIX apt-show-versions | sort > "$tmp_packages"
if diff -wEbBN "$BACKUP_DIR/$1".packages "$tmp_packages"; then
echo "$_NO_DEBIAN_PACKAGES_CHANGE"
fi | grep -v '^[0-9-]' >> "$tmp"
fi
if [ "$DO_DETAILS" = "yes" ]; then
echo "$FILES_DETAILS_HEADER" >> "$tmp"
# Just diff it!
set -o noglob
if (LC_ALL=$LOCALE diff -urBN $TAR_OPTS \
--minimal "$tmpdir"/`basename "$WATCHED_DIR"` \
"$WATCHED_DIR" 2>/dev/null); then
echo "$_NO_CHANGE"
fi | grep -v '^--- \|diff ' |
sed -e "s;^+++ $WATCHED_PARENT\([^ ]*\) .*;+++ \1;" \
>> "$tmp"
set +o noglob
fi
# Put on standard output
cat "$tmp"
# Clean temporaries
rm -rf "$tmp" "$tmpdir"
}
# Turns into stable the given testing.
# NB: argument validity is supposed to have been already checked.
stabilize_state() {
debug "* stabilize_state $@"
local testing stable file dst
testing="$1"
# follow symlink if needed
if [ -L "${BACKUP_DIR}/$testing".tar.bz2 ]; then
testing="`readlink ${BACKUP_DIR}/${testing}.tar.bz2`"
testing="`basename $testing | sed 's/\..*//'`"
fi
stable="`echo $testing | sed 's/^testing/stable/'`"
for file in "${BACKUP_DIR}/${testing}"*; do
dst="`echo $file | sed 's/\/testing-/\/stable-/'`"
cp "$file" "$dst"
# create/change stable-latest* links if, and only if,
# it's really the latest
if is_latest $stable; then
ln -sf "`basename $dst`" "${BACKUP_DIR}/`basename $dst |
sed 's/-[0-9]*\./-latest\./'`"
fi
done
if [ "${SEND_STABLE_REPORTS}" = yes ]; then
echo "metche saved a new stable state: $stable." |
email "$stable"
fi
}
# Print watched directory and files separated by spaces
# (suitable for find)
# Note: this function needs pathname expansion, but is called from places where
# it is disabled; that's why we need to save the pathname expansion status
# in the beginning and reset it to end with.
print_watched_files() {
local files
local reset_noglob_status_cmd
files="$WATCHED_DIR"
reset_noglob_status_cmd="`set +o | grep 'set .o noglob'`"
set +o noglob
if [ "$DO_CHANGELOGS" = "dir" ]; then
files="$files `echo "$CHANGELOG_DIR"/*/Changelog`"
elif [ "$DO_CHANGELOGS" = "file" ]; then
files="$files $CHANGELOG_FILE"
fi
$reset_noglob_status_cmd
echo "$files"
}
# Return true if watched files has not changed since $1 minutes
no_change_since() {
local time
time="$1"
set -o noglob
if [ -z "$(find $(print_watched_files) $FIND_OPTS -cmin "-$time" -print | head -1)" ]; then
set +o noglob
return 0
else
set +o noglob
return 1
fi
}
# Return true if watched files has changed since file $1 last modification
changed_from() {
local ref_file
ref_file="$1"
set -o noglob
if [ "$(find $(print_watched_files) $FIND_OPTS -newer "$ref_file" -print | head -1)" ]; then
set +o noglob
return 0
else
set +o noglob
return 1
fi
}
###
### Main
###
case "$CMD" in
report)
context_config "$VSNAME" || fatal "Aborting (error $?)."
DO_DETAILS="yes"
if [ -z "$MILESTONE" ]; then
report_changes "testing-latest"
elif milestone_exists "$MILESTONE"; then
report_changes "$MILESTONE"
else
display_usage
fatal "The specified state does not exist."
fi
;;
list)
context_config "$VSNAME" || fatal "Aborting (error $?)."
for file in "$BACKUP_DIR"/*.tar.bz2; do
echo `basename ${file%%.tar.bz2}`
done
;;
cron)
STABLE_TIME_MIN=`expr 24 '*' 60 '*' "$STABLE_TIME"`
if [ -n "$VSNAME" ]; then
display_usage
fatal "-h option not available for 'metche cron'"
fi
for i in "" $VSNAMES; do
res=0
context_config "$i" || res=$?
if [ $res -ne 0 ]; then
warning "-------- Ignoring" \
"`if [ -z $i ]; then \
echo 'the host system'; \
else \
echo VServer $i; fi` (error $res)"
continue
fi
### Algorithm
#
# if (no change happened for TESTING_TIME) then
# if (something has changed since the last testing) then
# send a report against last testing
# save a new testing state
# delete all saved unstable states
# elif (no change happened for STABLE_TIME) then
# if (something has changed since the last stable) then
# save a new stable state and notify EMAIL_ADDRESS
# delete all saved testing states older than STABLE_TIME
# fi
# fi
# elif (last unstable exists) then
# if (something has changed since the last unstable) then
# save a new unstable state
# fi
# else
# save a new unstable state
# fi
debug "* main algorithm"
if no_change_since "$TESTING_TIME"; then
debug " no change since TESTING_TIME"
if changed_from "$BACKUP_DIR"/testing-latest.tar.bz2; then
debug " changed from testing-latest"
report_changes "testing-latest" | email "testing-$DATE"
save_state "testing"
debug " removing all saved unstable states."
find "$BACKUP_DIR" -name 'unstable-*' -exec rm "{}" \;
elif no_change_since "$STABLE_TIME_MIN"; then
if changed_from "$BACKUP_DIR"/stable-latest.tar.bz2; then
save_state "stable"
if [ "${SEND_STABLE_REPORTS}" = yes ]; then
echo "metche saved a new stable state: stable-${DATE}." |
email "stable-$DATE"
fi
debug " removing all saved testing states older" \
"than STABLE_TIME ($STABLE_TIME)."
find "$BACKUP_DIR" -name 'testing-*' \
-ctime +"$STABLE_TIME" -exec rm "{}" \;
fi
fi
elif milestone_exists unstable-latest; then
if changed_from "$BACKUP_DIR"/unstable-latest.tar.bz2; then
debug " changed from unstable-latest"
save_state "unstable"
else
debug " not changed from unstable-latest"
fi
else
save_state "unstable"
fi
done
;;
stabilize)
context_config "$VSNAME" || fatal "Aborting (error $?)."
if [ -z "$MILESTONE" ]; then
stabilize_state "testing-latest"
elif [ "`milestone_version $MILESTONE`" = "testing" -a \
milestone_exists $MILESTONE ]; then
stabilize_state "$MILESTONE"
else
display_usage
fatal "The specified state is not an existing testing state."
fi
;;
test)
for i in "" $VSNAMES; do
res=0
context_config "$i" || res=$?
if [ $res -ne 0 ]; then
warning "-------- Ignoring" \
"`if [ -z $i ]; then \
echo 'the host system'; \
else \
echo VServer $i; fi` (error $res)"
continue
fi
milestone_version "stable-200507040202"
milestone_version "testing-latest"
milestone_date "testing-latest"
#report_changes "testing-latest" | email "testing-$DATE"
done
;;
*)
display_usage
exit 1
;;
esac
# vim: et sw=4