#!/bin/bash # # # --------------------------------------------------------------------------- # # Local Sync (for Gentoo) -- lclsync # # --------------------------------------------------------------------------- # # # # A script to update your local Gentoo portage tree with computers on the LAN # # and make maintenance easier. # # # # Checks a list of local IPs for a more recent Gentoo portage tree and then # # syncs with it, performs an update world, depclean & revdep-rebuild and # # eclean. # # # # Author: Graham Russell # # # # For the latest version please visit: http://ham1.co.uk/oss/gentoo/ # ############################################################################### readonly VERSION="1.03" readonly REVISION="$Revision$svnhack" readonly CURRENT_VERSION="$VERSION - Revision$REVISION" # safety bash settings set -o nounset # no unset variables set -o errexit # exit on any errors #################### # set up variables # #################### # program name-version-pid-(date in ns), should be rather unique readonly TEMP_FOLDER="/tmp/lclsync-$VERSION-$$-$(date +%N)" readonly IP_LIST="10.0.0.4 ibm server x56" readonly AGE_THRESHOLD=14 BEST_IP= BEST_IP_TIMESTAMP=0 LOCAL_TIMESTAMP=$(awk '{print $1}' /usr/portage/metadata/timestamp.x) TREE_AGE=$(( $(( $(date +%s)-$LOCAL_TIMESTAMP )) / 3600 )) SUDO= VERBOSE_SWITCH= ASK_SWITCH="-a" QUIET_REDIRECT= QUIET_FLAG="no" FIRST_FLAG="no" FORCE_FLAG="no" WEBSYNC_FLAG="no" DO_EVERYTHING="yes" SYNC_FLAG= UPDATE_FLAG= DEPCLEAN_FLAG= REVDEP_FLAG= ECLEAN_FLAG= #################### # set up constants # #################### readonly RED="\033[1;31m" readonly GREEN="\033[1;32m" readonly AMBER="\033[0;33m" readonly CYAN="\033[0;36m" readonly VIOLET="\033[1;35m" readonly WHITE="\033[1;37m" readonly NO_COLOUR="\033[0m" readonly TITLE_COLOUR=$WHITE readonly QUESTION_COLOUR=$CYAN readonly INFO_COLOUR="$AMBER" readonly ERR_COLOUR="$RED" readonly OK_COLOUR=$GREEN ######################### # some helper functions # ######################### function print_help { # prints the help... #if echo "Local Sync (for Gentoo) -- lclsync Checks a list of local IPs for a more recent Gentoo portage tree and then syncs with it, performs an update world and depclean See README for more information and examples. Author: Graham Russell Version: $CURRENT_VERSION Switches: -q quiet -v verbose -f force -- does without asking,non-interactive -s sync -- syncs -u update -- updates -d depclean -- depclean -r revdep -- revdep-rebuilds -e eclean -- does an eclean -1 first (1st) -- syncs with the first LAN server with a newer portage tree -a age -- prints the age of your portage tree -w webrsync -- does an emerge-webrsync instead of the normal \"emerge --sync\" -x debug mode -- enters crazy debug mode " } function lr_echo { # argument format: lr_echo(text, colour, echo-flag) # local rsync echo - wrapper function for echo if [[ $QUIET_FLAG != "yes" ]] then case "$#" in "0") echo ;; "1") echo -e "${1}${NO_COLOUR}" ;; "2") # works for lr_echo(text, colour) or lr_echo(text, echo-flag) echo -e $2 "${1}${NO_COLOUR}" ;; "3") echo -e $3 "${2}${1}${NO_COLOUR}" ;; *) lr_echo "Too many arguments given to lr_echo" $ERR_COLOUR ;; esac else if [ $# -gt 1 ] then if [ $ERR_COLOUR == $2 ] then echo -e "$2$1$NO_COLOUR" return fi fi fi } function quit { # cleans up temp folder # saves peppering the script with rm and ensures the script doesn't litter local exit_colour=$OK_COLOUR trap "" SIGINT SIGTERM EXIT lr_echo "\nQuit...\n" $TITLE_COLOUR lr_echo "Cleaning up temp files..." $INFO_COLOUR rm -rf $VERBOSE_SWITCH $TEMP_FOLDER if (( $1 != 0 )); then exit_colour=$ERR_COLOUR; fi lr_echo "Exiting with status $1" $exit_colour exit $1 } function reset_trap { # set up to trap ctrl-C and kill gracefully trap "lr_echo \"\n\n${ERR_COLOUR}AH! Caught SIGINT/TERM...\"; quit 1" SIGINT SIGTERM trap "quit $?" EXIT } function ask { # argument format: ask(question, action-if-yes, action-if-no) # Questions should be phrased such that positive answer result in an action local answer # force defaults questions to yes if [[ $FORCE_FLAG == "yes" ]] then eval "$2" # defaults to no in quiet mode elif [[ $QUIET_FLAG == "yes" ]] then eval "$3" else # asks user the question and takes appropriate action echo -e -n "\n${QUESTION_COLOUR}$1${NO_COLOUR} [${GREEN}Yes${NO_COLOUR}/${RED}No${NO_COLOUR}/Quit] " read answer lr_echo if echo $answer|grep -iq '^y' # yes then eval "$2" elif echo $answer| grep -iq '^q' # quit then quit 0 else # no (and everything else) eval "$3" fi fi } function sync { # function to sync the portage tree local sync_cmd="emerge --sync" if [[ $WEBSYNC_FLAG == "yes" ]] then sync_cmd="emerge-webrsync" if which emerge-delta-webrsync > /dev/null then lr_echo "apparently you have \"emerge-delta-webrsync\" installed, using it." $INFO_COLOUR sync_cmd="emerge-delta-webrsync" fi fi # sets up a new trap to ensure rsyncd gets started again trap "$SUDO /etc/init.d/rsyncd start; quit 1" INT TERM EXIT # prevents other people syncing with partial trees eval "$SUDO /etc/init.d/rsyncd stop $QUIET_REDIRECT" if [ $# -gt 0 ] && [[ $1 != " " ]] then export SYNC="rsync://$1/gentoo-portage" eval "$SUDO emerge --sync $QUIET_REDIRECT" unset SYNC else eval "$SUDO $sync_cmd $QUIET_REDIRECT" fi eval "$SUDO /etc/init.d/rsyncd start $QUIET_REDIRECT" reset_trap } ###################### # process parameters # ###################### # Based on http://www.ibm.com/developerworks/library/l-bash-parameters.html while getopts "fqvsudre1ahxw" optname do case "$optname" in "f") FORCE_FLAG="yes";ASK_SWITCH=; ;; "q") if [ ! -z $VERBOSE_SWITCH ] then echo "${RED}What are you doing? Verbose cancels out quiet!${NO_COLOUR}" sleep 2 else QUIET_REDIRECT="> /dev/null" # hides output, but prints errors QUIET_FLAG="yes" fi ;; "v") echo "Verbose flag on"; if [[ $QUIET_FLAG == "yes" ]] then echo "${RED}What are you doing? Verbose cancels out quiet!${NO_COLOUR}" sleep 2 QUIET_REDIRECT= QUIET_FLAG="no" fi VERBOSE_SWITCH="-v" ;; "s") SYNC_FLAG="yes"; DO_EVERYTHING="no" ;; "u") UPDATE_FLAG="yes"; DO_EVERYTHING="no" ;; "d") DEPCLEAN_FLAG="yes"; DO_EVERYTHING="no" ;; "r") REVDEP_FLAG="yes"; DO_EVERYTHING="no" ;; "e") ECLEAN_FLAG="yes"; DO_EVERYTHING="no" ;; "1") FIRST_FLAG="yes"; ;; "a") echo "Your portage tree is ~$TREE_AGE hour(s) old"; exit 1 ;; "h") print_help; exit 0; ;; "x") set -x; # crazy debug mode ;; "w") WEBSYNC_FLAG="yes" ;; "?") print_help exit 1 ;; ":") echo "No argument value for option $optarg" exit 1 ;; *) # Should not occur echo "Unknown error while processing options, bailing..."; exit 1; ;; esac done ################## # main functions # ################## function sync_main { local ip best_timestamp last_time older_by lr_echo "\nSynchronise tree...\n" $TITLE_COLOUR for ip in $IP_LIST do lr_echo "Checking $ip..." "-n" # ping IP, once, timeout 1 sec, no lookup of symbolic names if ping $ip -c 1 -w 1 -n >/dev/null then ############################################# # check time stamp of computers in the list # ############################################# # ensure a clean temp file environment rm -rf $VERBOSE_SWITCH $TEMP_FOLDER mkdir -p $VERBOSE_SWITCH $TEMP_FOLDER # ensures we cope if rsync isn't running on the IP set +e rsync rsync://$ip/gentoo-portage/metadata/timestamp.x $TEMP_FOLDER > /dev/null 2>&1 \ || \ { lr_echo "...rsync down?" $INFO_COLOUR; continue; } set -e best_timestamp=$(awk '{print $1}' $TEMP_FOLDER/timestamp.x) lr_echo "...${OK_COLOUR}ok" # move to next IP if it's not better than current best if [ $BEST_IP_TIMESTAMP -gt $best_timestamp ]; then continue; fi BEST_IP_TIMESTAMP=$best_timestamp BEST_IP=$ip if [[ $FIRST_FLAG == "yes" ]] then if [ $BEST_IP_TIMESTAMP -gt $LOCAL_TIMESTAMP ] then # stop checking the rest of the IPs if we # find a local sever with a newer tree break fi fi else # ping failed lr_echo "...${ERR_COLOUR}off" fi done lr_echo # sync with the most up-to date (best) local server if [ $BEST_IP_TIMESTAMP -ne 0 -a $BEST_IP_TIMESTAMP -gt $LOCAL_TIMESTAMP ] then # calculate a new age BEST_TREE_AGE=$(( $(($(date +%s) - $BEST_IP_TIMESTAMP)) / $((3600)) )) lr_echo "Younger tree (~$BEST_TREE_AGE hour(s)) found on $BEST_IP" $INFO_COLOUR # if sync is successful update the local time-stamp/tree age ask "Do you want to sync. with this tree? " \ "sync $BEST_IP && \ LOCAL_TIMESTAMP=$BEST_IP_TIMESTAMP && \ TREE_AGE=$BEST_TREE_AGE" \ " " else lr_echo "You have the youngest tree (~$TREE_AGE hours(s) old) available locally" $OK_COLOUR fi if [[ $FORCE_FLAG == "yes" ]] then sync return fi # check if the tree is too old if (( $TREE_AGE > $AGE_THRESHOLD )) then older_by=$(( $TREE_AGE - $AGE_THRESHOLD )) lr_echo "Your tree is $older_by hour(s) older than the threshold." $INFO_COLOUR # sync if forced ask "Shall I perform an external sync.? " \ "sync" \ "echo" else lr_echo "Not externally sync'ing, your tree younger than the threshold." $INFO_COLOUR fi } function update { lr_echo "Update packages..." $TITLE_COLOUR ask "emerge $ASK_SWITCH -vuDN world? " \ "$SUDO emerge $ASK_SWITCH -vuDN world $QUIET_REDIRECT " \ "" } function depclean { lr_echo "Clean packages..." $TITLE_COLOUR ask "emerge $ASK_SWITCH --depclean? " \ "$SUDO emerge $ASK_SWITCH --depclean $QUIET_REDIRECT " \ "" } function revdep { lr_echo "Check for missing dependencies..." $TITLE_COLOUR ask "revdep-rebuild (recommended after a depclean)? " \ "$SUDO revdep-rebuild $QUIET_REDIRECT " \ "" } function ecleandist { lr_echo "Clean installation files..." $TITLE_COLOUR ask "eclean-dist -pdn? " \ "$SUDO eclean-dist -pdn $QUIET_REDIRECT " \ "exit" ask "Perform the above actions with: eclean-dist -idn? " \ "$SUDO eclean-dist -idn" \ "exit" } ######## # main # ######## reset_trap # make sure we are interactive unless forced if [ ! -t 0 -a $FORCE_FLAG != "yes" ] then lr_echo "Terminal is non-interactive and force (-f) is not specified." $ERR_COLOUR touch lclsync_error.log echo -e "$(date):\nError when running $0:" > lclsync_error.log echo "Terminal wasn't interactive and -f wasn't specified" >> lclsync_error.log quit 1 fi # check user is root, else set SUDO variable to sudo so things that need to be # run as root are. if [[ $(id -nu) != "root" ]] then lr_echo "You are not root." $ERR_COLOUR lr_echo "This program runs sudo and may ask for your password..." $INFO_COLOUR sudo -v SUDO="sudo" fi # banner lr_echo " -------------------------------------- - lclsync (Local Sync) -- for Gentoo - --------------------------------------" $TITLE_COLOUR if [[ $DO_EVERYTHING == "yes" ]] then sync_main update depclean revdep ecleandist else if [[ $SYNC_FLAG == "yes" ]]; then sync_main; fi if [[ $UPDATE_FLAG == "yes" ]]; then update; fi if [[ $DEPCLEAN_FLAG == "yes" ]]; then depclean; fi if [[ $REVDEP_FLAG == "yes" ]]; then revdep; fi if [[ $ECLEAN_FLAG == "yes" ]]; then ecleandist; fi fi exit 0