#!/bin/sh
# coding: utf-8
#
## UPGRADE-SYSTEM -- Command for upgrading and sanitizing a Debian system.
#
## HOMEPAGE
#  http://q-funk.iki.fi/debian
#
## AUTHORS
#  Copyright © 2003-2004 Martin Zdrahal <martin.zdrahal@konflux.at>
#  Copyright © 2004,2012 Christoph Schindler <hop@30hopsmax.at>
#  Copyright © 2004-2012 Martin-Éric Racine <martin-eric.racine@iki.fi>
#
## LICENSE
#  GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
#
## DEPENDS
# *apt:apt-get (main/important) (>= 0.6.45: autoclean)(>= 0.7.0: --fix-policy).
#  coreutils:cut,rm,sort,tty (main/required).
# *deborphan:deborphan (universe/optional) (>= 1.7: --guess-doc --libdevel).
#  debsums:debsums (universe/optional).
#  dpkg:dpkg,dpkg-query (main/required).
#  grep:grep (main/required).
#  mawk:awk (main/required).
#  ncurses-bin:tput (main/required).
#  util-linux:setterm (main/required).
#
## CHANGES
#  2012-03-10   Make all APT checks quiet.      v1.6 [MER]
#  2012-03-06   Add autoremove to orphan purge. v1.5 [CS]
#  2011-12-21   Add APT --fix-policy install.   v1.5 [MER]
#  2011-03-03   Add debsum reinstallation.      v1.4 [MER]
#  2010-05-02   Add crude prompt colorization.  v1.3 [MER]
#  2009-08-08   Add obsolete config purge.      v1.2 [MER]
#  2009-06-21   Add uninstalled packages purge. v1.1 [MER]
#  2005-12-04   Use APT instead of DPKG purge.  v1.0 [MER]
#  2005-05-29   Add non-interactive detection.  v0.9 [MER]
#  2004-09-04   Make orphan purge recursive.    v0.8 [CS]
#  2004-08-19   Add APT exit code check.        v0.7 [MER]
#  2004-06-07   Add CLEANOPTS to config.        v0.6 [MER]
#  2004-03-31   Create config file.             v0.5 [MER]
#  2004-03-24   Add -y to dist-upgrade.         v0.4 [MER]
#  2004-03-15   Add --guess-doc --libdevel.     v0.3 [MER]
#  2004-03-09   Rename to upgrade-system.       v0.2 [MER]
#  2004-02-16   Initial release.                v0.1 [MZ]
##
#########################################
### INSERT EVENTUAL LOCALISATION HERE ###
#########################################
LANGUAGE=C
export LANGUAGE
LC_ALL=C
export LC_ALL
TEXTDOMAIN=upgrade-system
export TEXTDOMAIN
##########################
### SOURCE PREFERENCES ###
##########################
. /etc/upgrade-system.conf
########################
### SET SHELL COLORS ###
########################
BOLD=$(setterm -bold on)
RESET=$(setterm -default)
##DEPENDS: util-linux (main/required).
if [ -x /usr/bin/tput ] && tput setaf 1 >/dev/null 2>&1;
then
	RED=${BOLD}$(tput setaf 1)
	GREEN=${BOLD}$(tput setaf 2)
	YELLOW=${BOLD}$(tput setaf 3)
else
	RED=${BOLD}
	GREEN=${BOLD}
	YELLOW=${BOLD}
fi
##DEPENDS: ncurses-bin (main/required).
############################
### SET DEBCONF FRONTEND ###
############################
tty -s
##DEPENDS: coreutils (main/required).
if [ $? != 0 ]
then
	echo "${GREEN}N: Non-Interactive upgrade selected.${RESET}"
	NOTTY="-q -y -o DPkg::Options::=--force-confdef"
	DEBIAN_FRONTEND="noninteractive"
	export DEBIAN_FRONTEND
fi
############################
### UPDATE PACKAGE LISTS ###
############################
echo "${BOLD}1) Updating package lists:${RESET}"
apt-get $NOTTY -qq update
##DEPENDS: apt (main/important).
if [ $? != 0 ]
then
	echo "${RED}E: Some package lists could not be updated.${RESET}"
	exit 1
else
	echo "I: Package lists updated."
fi
########################
### UPGRADE PACKAGES ###
########################
echo "${BOLD}2) Checking for upgradable packages:${RESET}"
UPGRADABLE=$(apt-get $NOTTY $UPGRADEOPTS --simulate | awk '/^Inst / { print $2 }')
##DEPENDS: apt (main/important), mawk (main/required).
case $UPGRADABLE in
	"")
		echo "I: No upgradable package to install."
		break
		;;
	*)
		echo  "I: Installing upgradable packages..."
		apt-get $NOTTY $UPGRADEOPTS
		##DEPENDS: apt (main/important).
		if [ $? != 0 ]
		then
			echo "${RED}E: Some packages could not be upgraded.${RESET}"
			exit 2
		fi
		;;
esac
#############################
### PURGE ORPHAN PACKAGES ###
#############################
echo "${BOLD}3) Checking for orphan packages:${RESET}"
REMOVABLE=$(apt-get $NOTTY --purge --simulate autoremove | awk '/^Purg / { print $2 }')
##DEPENDS: apt (main/important), mawk (main/required).
# deborphan kludge (Debian #672829 and Ubuntu LP #940374).
while [ "${DEBORPHANS-undef}" != "$DEBORPHANS_OLD" ]
do
	DEBORPHANS_OLD=$DEBORPHANS
	DEBORPHANS=$(deborphan $ORPHANOPTS)
	##DEPENDS: deborphan (universe/optional).
	ORPHANS=${REMOVABLE:+$REMOVABLE }$DEBORPHANS
	REMOVABLE=""
	case $ORPHANS in
		"")
			echo "I: No orphan package to purge."
			break
			;;
		*)
			echo "I: Purging orphan packages..."
			apt-get $NOTTY --purge autoremove $ORPHANS
			##DEPENDS: apt (main/important).
			### Escape dangerous purges automatically.
			if [ $? != 0 ]
			then
			        break
			fi
			;;
	esac
done
####################################################################
### FLAUSCH'S SUPER CRUFT LIQUIDATOR -- USE WITH EXTREME CAUTION ###
####################################################################
# Check whether the FLAUSCH option is enabled in upgrade-system.conf
case $FLAUSCH in
	"")
		break
		;;
	*)
		echo "${YELLOW}W: FLAUSCH OPTION ENABLED. USE WITH EXTREME CAUTION!${RESET}"
		############################################
		### FIX DEPENDENCIES TO MATCH APT POLICY ###
		############################################
		echo "${BOLD}A) Checking for missing dependencies:${RESET}"
		FIXABLE=$(apt-get $NOTTY --auto-remove --fix-policy --purge --simulate install | awk '/^Inst / { print $2 }')
		##DEPENDS: apt (main/important), mawk (main/required).
		case $FIXABLE in
			"")
				echo "I: No missing dependency to install."
				break
				;;
			*)
				echo  "I: Installing missing dependencies..."
				apt-get $NOTTY --auto-remove --fix-policy --purge install -o Debug::pkgDepCache::AutoInstall=true
				##DEPENDS: apt (main/important).
				if [ $? != 0 ]
				then
					echo "${RED}E: Some dependencies could not be installed.${RESET}"
					exit 3
				fi
				;;
		esac
		##################################
		### PURGE UNINSTALLED PACKAGES ###
		##################################
		echo "${BOLD}B) Checking for uninstalled packages:${RESET}"
		while true
		do
			ORPHANS=$(dpkg -l | grep '^rc' | awk '{print $2}')
			##DEPENDS: dpkg (main/required), grep (main/required), mawk (main/required).
			case $ORPHANS in
				"")
					echo "I: No uninstalled package to purge."
					break
					;;
				*)
					echo "I: Purging uninstalled packages..."
					dpkg -P $ORPHANS
					##DEPENDS: dpkg (main/required).
					### Escape dangerous purges automatically.
					if [ $? != 0 ]
					then
			        		break
					fi
					;;
			esac
		done
		############################
		### PURGE ORPHAN CONFIGS ###
		############################
		echo "${BOLD}C) Checking for orphan configurations:${RESET}"
		# deborphan kludge (Debian #672829 and Ubuntu LP #940374).
		while [ "${ORPHANS-undef}" != "$ORPHANS_OLD" ]
		do
			ORPHANS_OLD=$ORPHANS
			ORPHANS=$(deborphan --find-config)
			##DEPENDS: deborphan (universe/optional).
			case $ORPHANS in
				"")
					echo "I: No orphan configuration to purge."
					break
					;;
				*)
					echo "I: Purging orphan configurations..."
					dpkg -P $ORPHANS
					##DEPENDS: dpkg (main/required).
					### Escape dangerous purges automatically.
					if [ $? != 0 ]
					then
					        break
					fi
					;;
			esac
		done
		#################################
		### REMOVING OBSOLETE CONFIGS ###
		#################################
		echo "${BOLD}D) Checking for obsolete configurations:${RESET}"
		ORPHANS=$(dpkg-query -W -f='${Conffiles}\n' | grep obsolete | awk {'print $1'})
		##DEPENDS: dpkg (main/required), grep (main/required), mawk (main/required).
		case $ORPHANS in
			"")
				echo "I: No obsolete configuration to purge."
				break
				;;
			*)
				echo "I: Removing obsolete configurations..."
				unique(){
					dpkg -S $ORPHANS | cut -d ':' -f 1 | uniq
					##DEPENDS: dpkg (main/required), coreutils (main/required), coreutils (main/required).
					}
				UNIQUE=$(unique)
				NUMBER=$(unique | wc -l)
				echo "I: Number of packages affected: $NUMBER."
				dpkg -S $ORPHANS
				##DEPENDS: dpkg (main/required).
				echo "${YELLOW}W: BEWARE OF FALSE POSITIVES! DELETE WITH EXTREME CAUTION!${RESET}"
				rm -i $ORPHANS
				##DEPENDS: coreutils (main/required).
				apt-get $NOTTY --reinstall install ${UNIQUE}
				##DEPENDS: apt (main/important).
				### Escape dangerous purges automatically.
				if [ $? != 0 ]
				then
				        break
				fi
				;;
		esac
		###############################################
		### REINSTALL PACKAGES WITH MISSING DEBSUMS ###
		###############################################
		if [ -x /usr/bin/debsums ]
		then
			echo "${BOLD}E) Checking for packages with missing debsums:${RESET}"
			while true
			do
				ORPHANS=$(dpkg -S 2>/dev/null $(debsums --list-missing --silent) | cut -d : -f 1 | sort -u)
				##DEPENDS: dpkg (main/required), debsums (universe/optional), coreutils (main/required).
				case $ORPHANS in
					"")
						echo "I: No package with missing debsums to reinstall."
						break
						;;
					*)
						echo "I: Reinstalling packages with missing debsums..."
						apt-get $NOTTY --reinstall install $ORPHANS
						##DEPENDS: apt (main/important).
						### Escape dangerous purges automatically.
						if [ $? != 0 ]
						then
			        			break
						fi
						;;
				esac
			done
		fi
		echo "${GREEN}N: FLAUSCH LOOP COMPLETED.${RESET}"
esac
####################################################################
#######################
### CLEAN APT CACHE ###
#######################
echo "${BOLD}4) Cleaning package cache.${RESET}"
apt-get $NOTTY $CLEANOPTS
##DEPENDS: apt (main/important).
echo "I: System upgrade completed."
#EOF
