#!/bin/bash

usage() {
  >&2 echo 'usage: update-me [-s|-c] [-u[ ]$user]'
  >&2 echo '  -s: play it save'
  >&2 echo '  -c: clear for exit'
  >&2 echo '  -u$user: safety-file should be owned by $user'
  exit 1
}

play_it_safe=false
safety_file='/tmp/update-me.do-not-exit'
flags="$*"

while [ $# -gt 0 ]; do
  case "x$1" in
    'x-s')
      play_it_safe=true
    ;;
    'x-c')
      if [ -f "${safety_file}" ] && ps $(cat "${safety_file}") >/dev/null; then
        rm "${safety_file}"
        exit 0
      fi
      if pgrep -x update-me | grep -vqxF $$; then
        exit 1
      else
        exit 2
      fi
    ;;
    'x-u'*)
      user="${1#-u}"
    ;;
    *)
      usage
    ;;
  esac
  shift
done

preCmds=('uname -n')
cmds=()
postCmds=('sync')

if command -v simply-report-installed-packages >/dev/null; then
  postCmds+=('simply-report-installed-packages')
fi

for mp in '/' '/boot'; do
  mountpoint -q "${mp}" || continue
  mount \
  | cut -d' ' -f3,6 \
  | grep "^${mp}\s" \
  | cut -d' ' -f2 \
  | grep -qwF 'ro' || continue
  [ "${mp}" = '/boot' ] && [ -d '/etc/ports' ] && continue
  preCmds+=('mount -o remount,rw '"${mp}")
  if command -v shutdownasap >/dev/null; then
    if command -v screen >/dev/null; then
      postCmds+=('mount -o remount,ro '"${mp}"' || screen -d -m shutdownasap -R')
    else
      postCmds+=('mount -o remount,ro '"${mp}"' || shutdownasap -R')
    fi
  else
    postCmds+=('bash -c "mount -o remount,ro '"${mp}"' || reboot"')
  fi
done

if command -v check-kernel >/dev/null; then
  postCmds+=('check-kernel -r')
fi

if command -v checkservices >/dev/null \
&& command -v systemctl >/dev/null; then
  postCmds+=('checkservices')
fi

command_needs_root() {
  local cmd
  cmd=$(
    printf '%s\n' "$1" \
    | sed '
      s@^bash -c "\(.*\)"$@\1@
      s@ .*$@@
      s@^.*/@@
    '
  )
  if [ "${cmd}" = 'checkservices' ] \
  || [ "${cmd}" = 'check-kernel' ] \
  || [ "${cmd}" = 'mount' ] \
  || [ "${cmd}" = 'report-installed-packages' ]; then
    return 0
  else
    return 1
  fi
}

opportunity_for_rescue_shell() {
  if "${play_it_safe}"; then
    printf '%s' "$$" >"${safety_file}"
    if [ -n "${user}" ] && [ "$(whoami)" != "${user}" ]; then
      chown "${user}" "${safety_file}"
    fi
    >&2 printf '%s: waiting for clearance ...' "$(uname -n)"
    while read -t 0.0001; do
      :
    done
    while [ -f "${safety_file}" ] && [ "$(cat "${safety_file}")" = "$$" ]; do
      if read -t 1; then
        >&2 printf ' rescue shell!\n'
        bash
        break
      fi
    done
    >&2 printf ' clear.\n'
    play_it_safe=false
  fi
}

exit_or_rescue_shell() {
  opportunity_for_rescue_shell
  if [ "$1" -eq 0 ]; then
    >&2 printf '%s: Erfolg\n' "$(uname -n)"
  else
    >&2 printf '%s: Fehler\n' "$(uname -n)"
  fi
  while read -t 0.0001; do
    :
  done
  read s
  if [ -n "${s}" ]; then
    bash
  fi
  exit "$1"
}

nochmal_versuchen() {
  >&2 printf '%s (%s): Fehler - nochmal versuchen?\n' "$(uname -n)" "${cmd}"
  while read -t 0.0001; do
    :
  done
  read s
  if [ -n "${s}" ]; then
    return 1
  else
    return 0
  fi
}

. /etc/update-me.conf

if ! command -v sudo >/dev/null; then
  hasSudo=false
fi

if [ ! "$(whoami)" == "root" ]; then
  if ! "${hasSudo}"; then
    uname -n
    err=1
    maxCount=3
    while [ ${err} -eq 1 ] && [ ${maxCount} -gt 0 ]
    do
      su -c "$(readlink -f "$0") ${flags} -u$(whoami) || exit 2"
      err=$?
      maxCount=$[${maxCount} - 1]
    done
    exit ${err}
  fi
  pre='sudo'
else
  pre=''
fi

if [ ${#cmds[@]} -eq 0 ]
then
  if [ -d '/etc/pacman.d' ]
  then
    cmds=('pacman -Syu' 'pacdiff')
  elif [ -d '/etc/ports' ]
  then
    cmds=('ports -u' 'prt-get --install-scripts sysup' 'rejmerge' 'revdep' '!makekernel')
  elif [ -d '/etc/apt' ]
  then
    cmds=('apt-get update' 'apt-get upgrade' 'apt-get dist-upgrade' 'apt-get autoremove')
  else
    >&2 echo 'Unknown distribution!'
    exit 1
  fi
fi

for cmd in "${preCmds[@]}"
do
  if command_needs_root "${cmd}"; then
    eval ${pre} ${cmd}
  else
    eval ${cmd}
  fi
  err=$?
  while [ ${err} -ne 0 ] && nochmal_versuchen; do
    if command_needs_root "${cmd}"; then
      eval ${pre} ${cmd}
    else
      eval ${cmd}
    fi
    err=$?
  done
  if [ ${err} -ne 0 ]
  then
    exit_or_rescue_shell ${err}
  fi
done

for cmd in "${cmds[@]}"
do
  if [ -z "${cmd##!*}" ]; then
    eval ${cmd#\!}
  else
    eval ${pre} ${cmd}
  fi
  err=$?
  while [ ${err} -ne 0 ] && nochmal_versuchen; do
    eval ${pre} ${cmd}
    err=$?
  done
  if [ ${err} -ne 0 ]; then
    exit_or_rescue_shell ${err}
  fi
done

opportunity_for_rescue_shell

for cmd in "${postCmds[@]}"
do
  if command_needs_root "${cmd}"; then
    eval ${pre} ${cmd}
  else
    eval ${cmd}
  fi
  err=$?
  while [ ${err} -ne 0 ] && nochmal_versuchen; do
    if command_needs_root "${cmd}"; then
      eval ${pre} ${cmd}
    else
      eval ${cmd}
    fi
    err=$?
  done
  if [ ${err} -ne 0 ]
  then
    exit_or_rescue_shell ${err}
  fi
done

exit_or_rescue_shell 0
