ArchLinux 2011.08 Upgrade

by tsrn
39 deployments · 6 still active · last rev. 4 years ago

Upgrade Arch 2011.08 to something more recent, and take care of the usual upgrade problems

Compatible with: No distros currently supported
						#!/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"