#!/bin/bash
# Recreate the files in /var/lib/dpkg/info/ from /var/lib/dpkg/status{,-old}
# Copyright 2015 TJ <ubuntu@iam.tj>
# Licenced on the terms of the GNU General Public Licence version 3

#   READY FOR USE

# use -x to enable debuging
set +x

# the directory to write the replacement files to
# over-ride this if fixing a chroot
TARGET=${TARGET:-/var/lib/dpkg}

function binary_installed()
{
  if ! which "$1" >/dev/null; then
    echo "Error: missing $1"
    exit 1
  fi
  return 0
}

for exe in dpkg-deb mktemp apt-get find awk readlink mv ls sudo rm; do
  binary_installed ${exe}
done

STATUS=${STATUS:-${TARGET}/status}
if [ ! -r "${STATUS}" ]; then
  if [ ! -r "${STATUS}-old" ]; then
    echo "Error: Cannot read ${STATUS}"
    exit 2
  else
    STATUS="${STATUS}-old"
    echo "Warning: No status file found; using backup ${STATUS}"
  fi
fi

TMP=$(mktemp -d)
if [ -z "{TMP}" ]; then
  echo "Error: failed to create temporary directory"
  exit 3
fi

pushd "${TMP}"

PKGS_INSTALLED="${TMP}/installed"
awk '/^Status: install ok installed/{print PKG; PKG=""} /^Package:/{PKG=$2}' "${STATUS}" | sort > "${PKGS_INSTALLED}"

if ! mkdir "${TMP}/info"; then
  echo "Error: cannot create directory ${TMP}/info"
  exit 5
fi

while read PKG; do
  echo -n "Checking package: ${PKG}"
  ARCH=$(awk '$0 == "Package: '${PKG}'"{P=1} P==1 && /^Architecture:/{ARCH=$2} P==1 && /^Multi-Arch:/{MULTIARCH=$2} P==1 && /^$/ {if(MULTIARCH == "same"){print ":" ARCH};exit}' "${STATUS}")

  if [ ! -f "${TARGET}/info/${PKG}${ARCH}.list" -o ! -f "${TARGET}/info/${PKG}${ARCH}.md5sums" ]; then
    echo " - needs repairing ..."  
    # test whether the package file is in apt's archive
    PKG_TMP=0
    PKG_ARCHIVE=$(readlink -e ${TARGET}/../../cache/apt/archives)
    PKG_MATCH="${PKG}_*${ARCH:1}.deb"
    PKG_BINARY=$(find ${PKG_ARCHIVE} -name "${PKG_MATCH}")
    if [ -z "${PKG_BINARY}" ]; then
      # No local package; need to download it
      apt-get download "${PKG}${ARCH}"
      PKG_BINARY=$(find $PWD -name "${PKG_MATCH}")
      if [ -z "${PKG_BINARY}" ]; then
        echo " Warning: repair failed; could not find or download ${PKG}${ARCH}"
        # abort processing and start on next package
        continue
      else
        PKG_TMP=1
      fi
    fi

    # remove the previous package's files
    rm -f "${TMP}/info/*"
    if [ ! -z "$(find "${TMP}/info/" -type f)" ]; then
      echo "Error: files not deleted"
      exit 6
    fi
    echo "Analysing binary package ${PKG_BINARY}"

    # generate the file list
    dpkg-deb -c ${PKG_BINARY} | awk ' {print substr($6,2)}' > "${TMP}/info/list"
    # clean up the file list
    sed -i -e 's,^/$,/.,' -e 's,/$,,' "${TMP}/info/list"

    # extract the control files
    dpkg-deb --control ${PKG_BINARY} "${TMP}/info"
    # control info is in the status file
    rm "${TMP}/info/control"
    # rename files with package name prefix
    while read FILE; do
      mv "$FILE" "${FILE%/*}/${PKG}${ARCH}.${FILE##*/}"
    done < <( find "${TMP}/info" -type f )
  
    ls --color "${TMP}/info/"
    # move the files into the dpkg directory
    echo "Moving replacement files into ${TARGET}/info/"
    sudo mv ${TMP}/info/* ${TARGET}/info/

    if [ ${PKG_TMP} -eq 1 ]; then
      # remove temporary binary package
      rm "${PKG_BINARY}"
    fi
  else
    echo " - looks OK"
  fi
done < "${PKGS_INSTALLED}"

echo "Removing temporary directory"
rm -rf ${TMP}

exit 0

