#!/bin/bash -u

#  CollectDebugInfo.sh
#  BackupLoupe
#
#  Created by Robby Pählig on 28.12.2018.

function collectLogs
{
    echo Collecting log files from "${log_path}"… | tee -a "${log}"

    if test "$(id -u)" == 0; then
        log_path=/Library/Logs/$product
    fi

    if [[ ! -d "${log_path}" ]]; then
        echo Log directory \""${log_path}"\" does not exist. Skipping. | tee -a "${log}"
    else
        subdir=Logs
        mkdir -p "${outdir}/${subdir}"
        for f in "${log_path}"/*; do
            if [[ "$f" == "${log_path}/*" ]]; then
                echo No files found. | tee -a "${log}"
                break
            fi
            echo Copying \""$f"\"… | tee -a "${log}"
            cp "${f}" "${outdir}/${subdir}"
        done
    fi
}

function collectCrashReports
{
    echo Collecting crash reports… | tee -a "${log}"

    subdir=Crash\ Reports
    mkdir -p "${outdir}/${subdir}"

    for f in "$crashreport_path"/*"${product}"*; do
        if [[ "$f" == "${crashreport_path}/*${product}*" ]]; then
            echo No files found. | tee -a "${log}"
            break
        fi
        echo "Copying \"$f\" …" | tee -a "${log}"
        cp "${f}" "${outdir}/${subdir}"
    done
}

function saveUserDefaults
{
    echo Saving user defaults… | tee -a "${log}"
    defaults export "${identifier}" "${outdir}/../${identifier}.plist"
}

function usage
{
    echo "Usage: $(basename "$0") IDENTIFIER OUTDIR USER (as root)"
	echo "       $(basename "$0") IDENTIFIER OUTDIR"
}

function processCacheItem
{
    ERR_OUT=$(/usr/bin/mktemp)

    if ! /bin/ls -leOd "$1" 2> "$ERR_OUT"; then
        echo -n "$1: Failed to list: "
        cat "$ERR_OUT"
    fi

    if ! /usr/bin/xattr -l "$1"; then
        echo -n "$1: Failed to read attributes: "
        cat "$ERR_OUT"
    fi

    /bin/rm "$ERR_OUT"

    echo
}

function collectCacheInfo
{
    echo Collecting cache info… | tee -a "${log}"

    if [[ $(/usr/bin/defaults read com.soma-zone.BackupLoupe superuserMode) == "1" ]]; then
        CACHE_DIR=$(/usr/libexec/PlistBuddy -c "Print :cacheDir" "/Library/Preferences/com.soma-zone.BackupLoupe.plist" )
        if test -z "$CACHE_DIR"; then
            CACHE_DIR="/Library/BackupLoupe"
        fi
    else
        CACHE_DIR=$(/usr/bin/defaults read com.soma-zone.BackupLoupe cachePath)
        if test -z "$CACHE_DIR"; then
            CACHE_DIR="$HOME/Library/BackupLoupe"
        fi
    fi

    CACHE_DIR="${CACHE_DIR/#\~/$HOME}"

    echo "Processing cache dir ${CACHE_DIR}…" | tee -a "${log}"

    export -f processCacheItem; /usr/bin/find "${CACHE_DIR}" -exec bash -c 'processCacheItem "$0"' {} \; > "${dir}/caches.txt"
}

echo Script was started at "$(date)" w/ uid "$(id -u)" and real uid "$(id -ur)": "$0" "$@"

identifier=$1
if [[ -z "${identifier}" ]]; then
    usage
	exit 1
fi

product="${identifier##*.}"
if [[ ! ${identifier} == *.* ]]; then
    echo "Invalid identifier: $identifier"
    exit 1
fi

outdir=$2
if [[ -z "${outdir}" ]]; then
    usage
    exit 1
fi

log="$(dirname "${outdir}")/collector.log"

if [[ $(id -u) == 0 ]]; then
    user=$3
    if test -z "$3"; then
        echo No user specified >&2
        usage
        exit 1
    fi
    if ! group=$(id -g "${user}"); then
        exit 1
    fi

    outdir="${outdir}/privileged"
    log_path=/Library/Logs/$product
    crashreport_path=/Library/Logs/DiagnosticReports
else
    outdir="${outdir}/unprivileged"
    log_path=~/Library/Logs/$product
    crashreport_path=~/Library/Logs/DiagnosticReports
fi

dir=$(dirname "${outdir}")
echo "Creating ${dir}" | tee -a "${log}"
mkdir -p "${outdir}"

echo "Creating ${dir}/mount.txt …" | tee -a "${log}"
/sbin/mount > "${dir}/mount.txt"
echo "Creating ${dir}/diskutil-list.txt …" | tee -a "${log}"
/usr/sbin/diskutil list > "${dir}/diskutil-list.txt"
echo "Creating ${dir}/diskutil-info.txt …" | tee -a "${log}"
/usr/sbin/diskutil info -all > "${dir}/diskutil-info.txt"
echo "Creating ${dir}/diskutil-apfs-list.txt …" | tee -a "${log}"
/usr/sbin/diskutil apfs list > /dev/null 2>&1 && /usr/sbin/diskutil apfs list > "${dir}/diskutil-apfs-list.txt"
echo "Creating ${dir}/hdiutil-info.txt …" | tee -a "${log}"
/usr/bin/hdiutil info > "${dir}/hdiutil-info.txt"
echo "Creating ${dir}/tmutil-destinationinfo.txt …" | tee -a "${log}"
/usr/bin/tmutil destinationinfo > "${dir}/tmutil-destinationinfo.txt"
echo "Creating ${dir}/tmutil-listbackups.txt …" | tee -a "${log}"
/usr/bin/tmutil listbackups > "${dir}/tmutil-listbackups.txt"
echo "Creating ${dir}/tmp-contents.txt …" | tee -a "${log}"
export -f processCacheItem; /usr/bin/find "/tmp/${identifier}" -exec bash -c 'processCacheItem "$0"' {} \; > "${dir}/tmp-contents.txt"
echo "Creating ${dir}/process-list.txt …" | tee -a "${log}"
/bin/ps auxwww | grep "[B]ackupLoupe" > "${dir}/process-list.txt"
echo "Collecting Full Disk Access information…" | tee -a "${log}"
echo "select client,client_type,auth_value,auth_reason,flags,last_modified from access where service = 'kTCCServiceSystemPolicyAllFiles'" | /usr/bin/sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db  > "${dir}/full-disk-access.txt"
if [[ $(id -u) == 0 ]]; then
    echo "Collecting Time Machine logs…" | tee -a "${log}"
    /usr/bin/log show --predicate 'subsystem == "com.apple.TimeMachine"' --info --last 7d | grep -v "Thermal pressure level" > "${dir}/time-machine.txt"
else
    collectCacheInfo
fi

collectLogs
collectCrashReports

if [[ $(id -u) == 0 ]]; then
    cp -v /Library/Preferences/com.apple.TimeMachine.plist "$(dirname "${outdir}")/" | tee -a "${log}"

    echo Setting permissions… | tee -a "${log}"
    chown -R "${user}":"${group}" "${dir}"
    pushd "$(dirname "${dir}")" > /dev/null

    echo Creating archive… | tee -a "${log}"
    tar cf "${dir}.tar" "$(basename "${dir}")"

    echo Cleaning up… | tee -a "${log}"
    rm -r "$(basename "${dir}")"

    echo Compressing archive… | tee -a "${log}"
    bzip2 -9 "$(basename "${dir}").tar"

    echo Archive "$(basename "${dir}").tar.bz2" created.
    open -R "$(basename "${dir}").tar.bz2"
else
    saveUserDefaults
fi
