Skip to content

Instantly share code, notes, and snippets.

@loganlinn
Created April 3, 2021 06:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loganlinn/51915851adef077316b3891d673c285f to your computer and use it in GitHub Desktop.
Save loganlinn/51915851adef077316b3891d673c285f to your computer and use it in GitHub Desktop.
Example 16-43. Updating FC4 - Advanced Bash-Scripting Guide
#!/bin/bash
# fc4upd.sh
# Script author: Frank Wang.
# Slight stylistic modifications by ABS Guide author.
# Used in ABS Guide with permission.
# Download Fedora Core 4 update from mirror site using rsync.
# Should also work for newer Fedora Cores -- 5, 6, . . .
# Only download latest package if multiple versions exist,
#+ to save space.
URL=rsync://distro.ibiblio.org/fedora-linux-core/updates/
# URL=rsync://ftp.kddilabs.jp/fedora/core/updates/
# URL=rsync://rsync.planetmirror.com/fedora-linux-core/updates/
DEST=${1:-/var/www/html/fedora/updates/}
LOG=/tmp/repo-update-$(/bin/date +%Y-%m-%d).txt
PID_FILE=/var/run/${0##*/}.pid
E_RETURN=85 # Something unexpected happened.
# General rsync options
# -r: recursive download
# -t: reserve time
# -v: verbose
OPTS="-rtv --delete-excluded --delete-after --partial"
# rsync include pattern
# Leading slash causes absolute path name match.
INCLUDE=(
"/4/i386/kde-i18n-Chinese*"
# ^ ^
# Quoting is necessary to prevent globbing.
)
# rsync exclude pattern
# Temporarily comment out unwanted pkgs using "#" . . .
EXCLUDE=(
/1
/2
/3
/testing
/4/SRPMS
/4/ppc
/4/x86_64
/4/i386/debug
"/4/i386/kde-i18n-*"
"/4/i386/openoffice.org-langpack-*"
"/4/i386/*i586.rpm"
"/4/i386/GFS-*"
"/4/i386/cman-*"
"/4/i386/dlm-*"
"/4/i386/gnbd-*"
"/4/i386/kernel-smp*"
# "/4/i386/kernel-xen*"
# "/4/i386/xen-*"
)
init () {
# Let pipe command return possible rsync error, e.g., stalled network.
set -o pipefail # Newly introduced in Bash, version 3.
TMP=${TMPDIR:-/tmp}/${0##*/}.$$ # Store refined download list.
trap "{
rm -f $TMP 2>/dev/null
}" EXIT # Clear temporary file on exit.
}
check_pid () {
# Check if process exists.
if [ -s "$PID_FILE" ]; then
echo "PID file exists. Checking ..."
PID=$(/bin/egrep -o "^[[:digit:]]+" $PID_FILE)
if /bin/ps --pid $PID &>/dev/null; then
echo "Process $PID found. ${0##*/} seems to be running!"
/usr/bin/logger -t ${0##*/} \
"Process $PID found. ${0##*/} seems to be running!"
exit $E_RETURN
fi
echo "Process $PID not found. Start new process . . ."
fi
}
# Set overall file update range starting from root or $URL,
#+ according to above patterns.
set_range () {
include=
exclude=
for p in "${INCLUDE[@]}"; do
include="$include --include \"$p\""
done
for p in "${EXCLUDE[@]}"; do
exclude="$exclude --exclude \"$p\""
done
}
# Retrieve and refine rsync update list.
get_list () {
echo $$ > $PID_FILE || {
echo "Can't write to pid file $PID_FILE"
exit $E_RETURN
}
echo -n "Retrieving and refining update list . . ."
# Retrieve list -- 'eval' is needed to run rsync as a single command.
# $3 and $4 is the date and time of file creation.
# $5 is the full package name.
previous=
pre_file=
pre_date=0
eval /bin/nice /usr/bin/rsync \
-r $include $exclude $URL | \
egrep '^dr.x|^-r' | \
awk '{print $3, $4, $5}' | \
sort -k3 | \
{ while read line; do
# Get seconds since epoch, to filter out obsolete pkgs.
cur_date=$(date -d "$(echo $line | awk '{print $1, $2}')" +%s)
# echo $cur_date
# Get file name.
cur_file=$(echo $line | awk '{print $3}')
# echo $cur_file
# Get rpm pkg name from file name, if possible.
if [[ $cur_file == *rpm ]]; then
pkg_name=$(echo $cur_file | sed -r -e \
's/(^([^_-]+[_-])+)[[:digit:]]+\..*[_-].*$/\1/')
else
pkg_name=
fi
# echo $pkg_name
if [ -z "$pkg_name" ]; then # If not a rpm file,
echo $cur_file >> $TMP #+ then append to download list.
elif [ "$pkg_name" != "$previous" ]; then # A new pkg found.
echo $pre_file >> $TMP # Output latest file.
previous=$pkg_name # Save current.
pre_date=$cur_date
pre_file=$cur_file
elif [ "$cur_date" -gt "$pre_date" ]; then
# If same pkg, but newer,
pre_date=$cur_date #+ then update latest pointer.
pre_file=$cur_file
fi
done
echo $pre_file >> $TMP # TMP contains ALL
#+ of refined list now.
# echo "subshell=$BASH_SUBSHELL"
} # Bracket required here to let final "echo $pre_file >> $TMP"
# Remained in the same subshell ( 1 ) with the entire loop.
RET=$? # Get return code of the pipe command.
[ "$RET" -ne 0 ] && {
echo "List retrieving failed with code $RET"
exit $E_RETURN
}
echo "done"; echo
}
# Real rsync download part.
get_file () {
echo "Downloading..."
/bin/nice /usr/bin/rsync \
$OPTS \
--filter "merge,+/ $TMP" \
--exclude '*' \
$URL $DEST \
| /usr/bin/tee $LOG
RET=$?
# --filter merge,+/ is crucial for the intention.
# + modifier means include and / means absolute path.
# Then sorted list in $TMP will contain ascending dir name and
#+ prevent the following --exclude '*' from "shortcutting the circuit."
echo "Done"
rm -f $PID_FILE 2>/dev/null
return $RET
}
# -------
# Main
init
check_pid
set_range
get_list
get_file
RET=$?
# -------
if [ "$RET" -eq 0 ]; then
/usr/bin/logger -t ${0##*/} "Fedora update mirrored successfully."
else
/usr/bin/logger -t ${0##*/} \
"Fedora update mirrored with failure code: $RET"
fi
exit $RET
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment