#!/bin/bash
# Author: Tomas M. <http://www.slax.org/>
# Author: crims0n <https://minios.dev>

VERSION="1.0"
BEXT="sb"
COMP_TYPE="zstd"
export TEXTDOMAIN="minios-tools"
TMP=/tmp/changes$$
EXCLUDE="^\$|/\$|[.]wh[.][.]wh[.]orph/|^[.]wh[.][.]pwd[.]lock|^[.]wh[.][.]wh[.]plnk/|^[.]wh[.][.]wh[.]aufs|^var/cache/|^var/backups/|^var/tmp/|^var/log/|^var/lib/apt/|^var/lib/dhcp/|^var/lib/systemd/|^sbin/fsck[.]aufs|^etc/resolv[.]conf|^root/[.]Xauthority|^root/[.]xsession-errors|^root/[.]fehbg|^root/[.]fluxbox/lastwallpaper|^root/[.]fluxbox/menu_resolution|^etc/mtab|^etc/fstab|^boot/|^dev/|^mnt/|^proc/|^run/|^sys/|^tmp/"
CHANGES=/run/initramfs/memory/changes

help() {
   echo "$(gettext "Usage"): $(basename $0) [OPTIONS] target_file.$BEXT [changes_directory]"
   echo "$(gettext "Saves all changed files in a compressed filesystem bundle.")"
   echo ""
   echo "$(gettext "Options"):"
   echo "  -c, --comp TYPE        $(gettext "Compression type (zstd, gzip, lzo, xz). Default: zstd")"
   echo "  -b, --bext EXT         $(gettext "Bundle extension. Default: sb")"
   echo "      --help             $(gettext "Display this help and exit")"
   echo "      --version          $(gettext "Display version information and exit")"
   echo ""
   echo "$(gettext "If changes_directory is not specified,")"
   echo "$(gettext "/run/initramfs/memory/changes is used.")"
   echo ""
   exit 0
}

brief_help() {
   echo "$(gettext "Usage"): $(basename $0) [OPTIONS] target_file.$BEXT [changes_directory]"
   echo "$(gettext "Try") '$(basename $0) --help' $(gettext "for more information.")"
   exit 1
}

version() {
   echo "$(basename $0) $VERSION"
   exit 0
}

while [[ $# -gt 0 ]]; do
   key="$1"

   case $key in
   -c | --comp)
      COMP_TYPE="$2"
      shift 2
      ;;
   -b | --bext)
      BEXT="$2"
      shift 2
      ;;
   --help)
      help
      ;;
   --version)
      version
      ;;
   *) # unknown option
      TARGET="$1"
      shift
      if [[ $# -gt 0 ]]; then
         CHANGES="$1"
         shift
      fi
      ;;
   esac
done

if [[ "$(id -u)" != "0" ]]; then
   echo "This script must be run as root." >&2
   brief_help
fi

if [[ -z "$TARGET" ]]; then
   brief_help
fi

# Overlayfs requires one more subdir. Detect it this way
if [ -d "$CHANGES/changes" ] && [ -d "$CHANGES/workdir" ] && [ "$(ls -1 "$CHANGES" | egrep -v '^changes$' | egrep -v '^workdir')" = "" ]; then
   CHANGES="$CHANGES/changes"
fi

# exclude control files for automounted disk drives
EXCLUDEDISKS=$(grep "Skip savechanges" /etc/systemd/system/{*,*/*} 2>/dev/null | cut -d : -f 1 | cut -b 2- | tr '\n' '|')
if [ -n "$EXCLUDEDISKS" ]; then
   EXCLUDE="$EXCLUDE|^($EXCLUDEDISKS)\$"
fi

# exclude the save_file itself of course
EXCLUDE="$EXCLUDE|^$(readlink -f "$TARGET" | cut -b 2- | sed -r "s/[.]/[.]/")\$"

CWD=$(pwd)

cd "$CHANGES" || exit

mkdir -p "$TMP"
mount -t tmpfs tmpfs "$TMP"

find \( -type d -printf "%p/\n" , -not -type d -print \) |
   sed -r "s/^[.]\\///" | egrep -v "$EXCLUDE" |
   while read FILE; do
      cp --parents -afr "$FILE" "$TMP"
   done

cd "$CWD"

if [ "$COMP_TYPE" = "zstd" ]; then
   COMP_OPTS="-Xcompression-level 19"
elif [ "$COMP_TYPE" = "xz" ]; then
   COMP_OPTS="-Xbcj x86"
else
   COMP_OPTS=""
fi

mksquashfs "$TMP" "$TARGET" -comp "$COMP_TYPE" -b 1024K -always-use-fragments -noappend -quiet $COMP_OPTS

umount "$TMP"
rmdir "$TMP"
