#!/bin/sh
# FreeBSD system port upgrade script
#
# Licence: BSDLike - http://rickvanderzwet.nl/LICENSE
# Rick van der Zwet <info@rickvanderzwet.nl>

. /etc/rc.subr

# Pointers to avoid confusion co-respond with logical boolean style values.
# WARNING do not compare with exit codes!
FALSE=0
TRUE=1

ask_question() {
  # Will return 1 if yes, return 0 if no
  QUESTION=$1
  DEFAULT=$2
  echo -n "$QUESTION? [$DEFAULT]: "; read INPUT
  INPUT=${INPUT:-"${DEFAULT}"}
  checkyesno INPUT || return 1 && return 0

}

echo_list() {
  PREFIX=$1
  shift
  for ENTRY in $*; do
    echo "$PREFIX $ENTRY"
  done
}


#
# SuperCow power only
if [ `id -u` -ne 0 ]; then
    echo "Sorry root only" 1>&2
    exit 128
fi

# Make sure we always using the latest version
CHANGES=`svn up --non-interactive $(dirname $0) | wc -l`
if [ $CHANGES -gt 1 ]; then
  sh $0
  exit 0
fi

#
# Check which ports-mgnt tool to use to upgrade outdated ports
#
FORCE_PORTUPGRADE=${FORCE_PORTUPGRADE:-$FALSE}
FORCE_PORTMASTER=${FORCE_PORTMASTER:-$FALSE}

PORTUPGRADE_INSTALLED=$FALSE
PORTMASTER_INSTALLED=$FALSE
USE_PORTMGNT="none"
if [ -n "`whereis -qb portupgrade`" ]; then
  PORTUPGRADE_INSTALLED=$TRUE
fi
if [ -n "`whereis -qb portmaster`" ]; then
  PORTMASTER_INSTALLED=$TRUE
fi

if [ $FORCE_PORTMASTER -eq $TRUE ]; then
  if  [ $PORTMASTER_INSTALLED -eq $FALSE ]; then 
    echo "# ERROR: FORCE_PORTMASTER set but binary not found"
    exit 1
  fi
  USE_PORTMGNT="portmaster"
elif [ $FORCE_PORTUPGRADE -eq $TRUE ]; then
  if [ $PORTUPGRADE_INSTALLED -eq $FALSE ]; then 
    echo "# ERROR: FORCE_PORTUPGRADE set but binary not found"
    exit 1
  fi
  USE_PORTMGNT="portupgrade"
else
  if [ $PORTUPGRADE_INSTALLED -eq $TRUE ]; then
    if [ $PORTMASTER_INSTALLED -eq $TRUE ]; then
      echo "# ERROR: both portmaster and portupgrade are installed"
      echo "# Pick your favorite by setting either FORCE_PORTMASTER=1 or FORCE_PORTUPGRADE=1"
      exit 1
    fi
    USE_PORTMGNT="portupgrade"
  else
    if [ $PORTMASTER_INSTALLED -eq $FALSE ]; then
      echo "# WARNING: ports-mgnt/portupgrade not found!" 
      echo "# WARNING: ports-mgnt/portmaster not found!" 
      echo "# ERROR  : Not port upgrade tool installed"
      exit 1
    fi
    USE_PORTMGNT="portmaster"
  fi
fi


 


DIRNAME=`dirname $0`
BATCH=${BATCH-""}

# Get list of rc.d marked for updates
RC_FILES=`$DIRNAME/port-list.sh`
RUNNING_DAEMONS=""

for RC_FILE in $RC_FILES; do 
  $RC_FILE onestatus | grep -q 'is running as' && {
    RUNNING_DAEMONS="$RUNNING_DAEMONS $RC_FILE"
  }
done

# Update port tree
echo "# Updating portstree ..."
portsnap update > /dev/null

# Update ports listing
echo "# Checking ports which needs updating ..."
NEWPORTS=`pkg_version -qol '<'`

# Check for potentional trouble.
# XXX: Weird -q does not strip at '!' check
BROKENPORTS=`pkg_version -qol '!' | awk '{print $1}'`
if [ -n "$BROKENPORTS" ]; then
  echo "# WARNING comparion failed, fix by hand"; echo_list "# - " $BROKENPORTS
fi


if [ -z "$NEWPORTS" ]; then
  echo "# No ports to update"
  echo "# All done, goodbye"
  exit 0
fi

# Check for broken pkgdb, else we have trouble during upgrades
if [ $USE_PORTMGNT = "portupgrade" ]; then
  pkgdb -a || exit 1
fi

#
# Update ports
if [ -z "$BATCH" ]; then
  # Make sure we have read the (new) UPDATING announcements
  # Use ls to display the last motification time of the directories in
  # /var/db/pkg and assume that is the last time the user read the 
  # UPDATING file
  LAST_UPDATED=`ls -rtlD '%Y%m%d' /var/db/pkg/ | awk 'END{print $6}'`

  # Find new entries
  TMPFILE=`mktemp -t $(basename $0).XXX`
  awk -F: -v last=$LAST_UPDATED '{if (match($0,"^[0-9]+:$") && $1 < last) {exit}; print $0}' /usr/ports/UPDATING > $TMPFILE

  echo "# Show new /usr/ports/UPDATING entries (starting from $LAST_UPDATED) ..."
  if [`cat $TMPFILE | wc -l` -eq 7 ]; then
    echo "## No new entries found"
  else
   cat $TMPFILE
  fi
  rm $TMPFILE
  
  # agree to the terms of the game
  echo "# Ports pending update:"
  echo_list "# - " $NEWPORTS
  ask_question "# Do you like to upgrade the affected ports" "no" || exit 1

  #
  # Stop daemons
  DAEMONS_STOPPED=$FALSE
  if [ -n "$RC_FILES" ]; then
    echo "# Affected daemons:"; echo_list "# - " $RC_FILES
    if [ -n "$RUNNING_DAEMONS" ]; then
      echo "# Running  daemons:"; echo_list "# - " $RUNNING_DAEMONS
      ask_question "# Do you like to stop running daemons" "yes" && {
        for RC_FILE in $RUNNING_DAEMONS; do
          $RC_FILE stop
        done;
        DAEMONS_STOPPED=$TRUE
      }
    fi
  fi
fi
echo "# Using update tool '$USE_PORTMGNT"
case $USE_PORTMGNT in 
  portupgrade)
    portupgrade -r -mBATCH=yes -a $NEWPORTS
    ;;
  portmaster)
    portmaster -d --no-confirm --no-term-title --no-index-fetch -mBATCH=yes -a $NEWPORTS
    ;;
  *)
    echo "# ERROR: Failed to find a port management tool"
    exit 1
    ;;
esac

echo "# Ports updated:"
echo_list "# - " $NEWPORTS
#
# (Re)start daemons. Assume we only like to start the just stopped ones.
if [ -n "$RC_FILES" ]; then
  echo "# Affected daemons:"; echo_list "# - " $RC_FILES
  if [ -n "$RUNNING_DAEMONS" ]; then
    if [ $DAEMONS_STOPPED -eq $TRUE ]; then
      echo "# Enabled daemons: "; echo_list "# - " $RUNNING_DAEMONS
      ask_question "# Do you like to start your daemons" "yes" && {
        for RC_FILE in $RUNNING_DAEMONS; do
          $RC_FILE start 
        done
      }
    else
      echo "# Running daemons: "; echo_list "# - " $RUNNING_DAEMONS
      ask_question "# Do you like to restart your daemons" "yes" && {
        for RC_FILE in $RUNNING_DAEMONS; do
          $RC_FILE restart 
        done
      }
    fi
  fi
fi

echo "# All done, goodbye"
