Upgrade Arch 2011.08 to something more recent, and take care of the usual upgrade problems
#!/bin/bash
# <UDF name="sshpubkey" label="SSH public key for root login" example="ssh-rsa ABCD..."/>
# <UDF name="fqdn" label="Server's Fully Qualified Doamin Name" example="server.domain.tld" />
# <UDF name="timezone" label="Server's Timezone" default="America/Chicago" example="America/New_York" />
# <UDF name="locale" label="System locale" default="en_US.UTF-8" example="en_GB.UTF-8" />
# <UDF name="mirrorlist" label="Pacman mirrors from which countries?" manyOf="Australia,Belarus,Belgium,Brazil,Bulgaria,Canada,Chile,China,Colombia,Czech Republic,Denmark,Estonia,Finland,France,Germany,Greece,Hungary,India,Indonesia,Ireland,Israel,Italy,Japan,Kazakhstan,Korea,Latvia,Luxembourg,Macedonia,Netherlands,New Caledonia,Norway,Poland,Portugal,Romania,Russian Federation,Serbia,Singapore,Slovakia,South Africa,Spain,Sri Lanka,Sweden,Switzerland,Taiwan,Turkey,Ukraine,United Kingdom,United States,Uzbekistan,Viet Nam" default="United States" />
## Use this to build timezone listing
## awk '$1 !~ /^#/{fields[i++]=$3};END{n=asort(fields); result=fields[1]; for (i=2; i<=n; i++) result=result", "fields[i]; print result}' /usr/share/zoneinfo/zone.tab
## Use this to build Pacman mirror listing
## curl -s 'http://www.archlinux.org/mirrorlist/?country=all&protocol=ftp&protocol=http&ip_version=4&ip_version=6' | awk -F"," 'NR>5 && $1 ~ /^##/{gsub(/## /,"");fields[i++]=$1};END{n=asort(fields); result=fields[1]; for (i=2; i<=n; i++) result=result","fields[i]; print result}'
: ${LOGFILE:=/root/arch-upgrade.log}
: ${DEBUG:=true}
write_msg() {
local msg="$1"
printf -- "${msg}\n" | tee -a $LOGFILE
}
write_log() {
local msg="$1"
printf -- "${msg}\n" >> $LOGFILE
}
write_info() {
local msg="$1"
write_msg "[II] ${msg}"
}
write_notice() {
local msg="$1"
write_msg "\n[!!] ${msg}"
}
write_err() {
local msg="$1"
write_msg "\n[EE] ${msg}"
}
write_head() {
local msg="$1"
write_msg "\n[--] ${msg}"
}
write_task() {
local msg="$1"
write_msg "\t--> ${msg}"
}
init_config() {
## Get hostname
HOSTNAME=$(echo $FQDN | cut -d. -f1)
## Set base locale
LOCALE_BASE=$(echo $LOCALE | cut -d. -f1)
## Get a sensible locale (in case the selected one doesn't exist)
grep "^${LOCALE}" /etc/locale.gen &>/dev/null
(( $? > 0 )) && LOCALE=${LOCALE_BASE}
grep "^${LOCALE}" /etc/locale.gen &>/dev/null
if (( $? > 0 ))
then
LOCALE="en_US.UTF-8"
LOCALE_BASE="en_US"
fi
echo "LANG=$LOCALE" > /etc/locale.conf
## Set timezone to sensible value (in case the selected one doesn't exist)
grep "${TIMEZONE}" /usr/share/zoneinfo/zone.tab &>/dev/null
(( $? > 0 )) && TIMEZONE="America/Chicago"
## Get architecture
arch="$(uname -m)"
if [[ "$arch" == "i386" ]]
then
arch="i686"
fi
## Get IP addresses on system
IPADDR=( $(ip -f inet -r addr | awk '$1 ~ /^inet$/{split($2,arr,"/");if (arr[1] != "127.0.0.1") print arr[1]}') )
IPADDR6=( $(ip -f inet6 -r addr | awk '$2 ~ /^2600/{split($2,arr,"/");if (arr[1] != "::1") print arr[1]}') )
## Build sed edit lines
[[ "$arch" == "x86_64" ]] && sed_multilib_pacmanconf="\|\[multilib[^-]"
[[ ! -z ${MIRRORLIST} ]] && readarray MIRRORS <<< "${MIRRORLIST/,/$'\n'}"
sed_pacman_mirrorlist="/## \(Any"
for MIRROR in "${MIRRORS[@]%$'\n'}"
do
sed_pacman_mirrorlist="${sed_pacman_mirrorlist}\|${MIRROR}"
done
sed_pacman_mirrorlist="${sed_pacman_mirrorlist}\)/,/^\$/{s/#\(Server.*\)/\1/;p}"
sed_repos_pacmanconf="/\(#*\(\[core\|\[extra\|\[community[^-]${sed_multilib_pacmanconf}\)\)/,+2{s/^#*\(.*\)/\1/}"
num_cpus=$(awk '/^processor/{count++}END{print count}' /proc/cpuinfo)
if [[ ! -z $SSHPUBKEY ]]
then
mkdir -p /root/.ssh
echo "$SSHPUBKEY" >> /root/.ssh/authorized_keys
chmod -R 600 /root/.ssh
fi
## Save install environment for later diagnosis
set > /root/.install-env
printf "" > $LOGFILE
}
sanity_check() {
declare error=0
if [[ ! -e /etc/arch-release ]]
then
write_err "Unsupported installation, cannot continue"
exit 1
fi
if [[ -z ${IPADDR} ]]
then
error=1
write_err "IP addresses not configured"
else
host mirrors.kernel.org &> /dev/null
if (( $? > 0 ))
then
error=1
write_err "Could not resolve mirrors.kernel.org"
else
wget http://mirrors.kernel.org/archlinux/core/os/${arch}/core.db -q -O /dev/null
if (( $? > 0 ))
then
error=1
write_err "Could not retrieve pacman package database"
fi
fi
fi
return $error
}
banner() {
write_msg ""
write_msg "-- ArchLinux 2011.08 Upgrader v1.0"
write_head "OS Information"
write_info "Architecture: ${arch}"
write_info "CPUs: ${num_cpus}"
write_head "Network Information"
write_info "IP Addresses: ${IPADDR[*]}"
write_info "IPv6 Addresses: ${IPADDR6[*]}"
write_info "Main IPv4: ${IPADDR[0]}"
write_info "Main IPv6: ${IPADDR6[0]}"
write_info "Hostname: ${HOSTNAME}"
}
run_cmd() {
prio="$1"; shift
msg="$1"; shift
case $prio in
info|err|task|notice ) write_$prio "$msg"
;;
* ) write_msg "$msg"
;;
esac
exec 2>>$LOGFILE
[[ "$DEBUG" == "true" ]] && set -x
"$@" 1>&2
ret=$?
set +x
exec 2>&-
return $ret
}
### Initialize and show the banner
init_config
banner
### Sanity check
### The script will die if the error is not recoverable
### and it will sleep until fixed otherwise
sanity_check
if (( $? > 0 ))
then
write_notice "Sanity check failed!"
run_cmd task "Sleeping until fixed..." sleep 60
fi
### Start the upgrade
write_msg "\n ---- STARTING UPGRADE ----\n"
write_head "Preparing upgrade"
run_cmd task "Initial Pacman DB sync" pacman -Syq
run_cmd task "Disable package auto-updates" sed -i 's/^\(SyncFirst.*\)/#\1/' /etc/pacman.conf
run_cmd task "Removing module-init-tools" pacman -Rdd --noconfirm module-init-tools
run_cmd task "Force-upgrading packages" pacman -Sf --noconfirm filesystem glibc initscripts
write_head "Setting locales"
run_cmd task "Moving new locale.gen in place" mv /etc/locale.gen{.pacnew,}
run_cmd task "Enabling en_US locales" sed -i "s/^#\(en_US.*\)/\1/" /etc/locale.gen
if [[ "${LOCALE_BASE}" != "en_US" ]]
then
run_cmd task "Enabling ${LOCALE_BASE} locales" sed -i "s/^#\(${LOCALE_BASE}.*\)/\1/" /etc/locale.gen
fi
run_cmd task "Regenerating locales" locale-gen
write_head "Upgrading pacman"
run_cmd task "Upgrading package" pacman -S --noconfirm pacman
run_cmd task "Moving new config in place" mv /etc/pacman.conf{.pacnew,}
write_head "Installing HAVEGED"
run_cmd task "Installing package" pacman -S --noconfirm haveged
run_cmd task "Starting daemon" rc.d start haveged
write_head "Enabling Pacman signed repositories"
run_cmd task "Creating new local key" pacman-key --init
run_cmd task "Downloading developer list" wget -q -O /root/developers.html https://www.archlinux.org/developers/
run_cmd task "Downloading 'trusted user' list" wget -q -O /root/trustedusers.html https://www.archlinux.org/trustedusers/
run_cmd task "Converting developer list" awk -F\" '(/pgp.mit.edu/) {sub(/.*search=0x/,"");print $1>>"/etc/pacman.d/trusted-keys"}' /root/developers.html
run_cmd task "Converting 'trusted user' list" awk -F\" '(/pgp.mit.edu/) {sub(/.*search=0x/,"");print $1>>"/etc/pacman.d/trusted-keys"}' /root/trustedusers.html
run_cmd task "Importing developer and 'trusted user' keys" pacman-key --recv-keys $(cat /etc/pacman.d/trusted-keys)
run_cmd task "Refreshing all keys" pacman-key --refresh-keys
run_cmd task "Enabling package signature checking" sed -i -e 's/^#\(SigLevel = Optional TrustAll\)/\1/' -e 's/\(SigLevel = Never\)/#\1/' /etc/pacman.conf
run_cmd task "Enabling repo signature checking" sed -i "$sed_repos_pacmanconf" /etc/pacman.conf
run_cmd task "Cleaning up" rm -fv /root/{developers,trustedusers}.html
write_head "Configuring Pacman mirrors"
run_cmd task "Downloading new mirrorlist" wget -O /etc/pacman.d/mirrorlist 'http://www.archlinux.org/mirrorlist/?country=all&protocol=ftp&protocol=http&ip_version=4&ip_version=6'
run_cmd task "Adding mirrors.kernel.org to mirrors" sed -i '$ a\
## Any \
Server = ftp://mirrors.kernel.org/archlinux/$repo/os/$arch \
Server = http://mirrors.kernel.org/archlinux/$repo/os/$arch \
' /etc/pacman.d/mirrorlist
run_cmd task "Filtering mirrorlist" sed -i.orig -n "$sed_pacman_mirrorlist" /etc/pacman.d/mirrorlist
write_head "Full system upgrade"
run_cmd task "Re-syncing package databases" pacman -Syq
run_cmd task "Starting upgrade" pacman -Syyu --noconfirm
run_cmd task "Cleaning up" rm -fv /etc/pacman.d/mirrorlist.pacnew
write_head "Updating boot configuration"
run_cmd task "Getting fresh rc.conf" wget -O /etc/rc.conf https://projects.archlinux.org/initscripts.git/plain/rc.conf
run_cmd task "Setting hardware clock" sed -i "s/\(HARDWARECLOCK=\).*/\1UTC/" /etc/rc.conf
run_cmd task "Setting timezone" sed -i "s/\(TIMEZONE=\).*/\1${TIMEZONE/\//\\/}/" /etc/rc.conf
run_cmd task "Setting keymap" sed -i "s/\(KEYMAP=\).*/\1us/" /etc/rc.conf
run_cmd task "Setting consolefont" sed -i "s/\(CONSOLEFONT=\).*/\1LatArCyrHeb-14/" /etc/rc.conf
run_cmd task "Setting colsolemap" sed -i "s/\(CONSOLEMAP=\).*/\18859-1/" /etc/rc.conf
run_cmd task "Setting hostname" sed -i "s/\(HOSTNAME=\).*/\1$FQDN/" /etc/rc.conf
run_cmd task "Setting network interface" sed -i "s/\(interface=\).*/\1eth0/" /etc/rc.conf
run_cmd task "Setting startup services" sed -i '/\(DAEMONS=\).*/{s/\(syslog-ng\s.*\(network\s\)\).*\(crond\)/!hwclock \1sshd haveged \2/}' /etc/rc.conf
run_cmd task "Adding addresses to /etc/hosts" sed -i "/^# End of file/{s/^/${IPADDR[0]} ${HOSTNAME} ${FQDN}\n${IPADDR6[0]} ${HOSTNAME} ${FQDN}\n\n/;}" /etc/hosts
run_cmd task "Cleaning up" rm -fv /etc/rc.conf.pacnew
write_notice "Upgrade Complete"