#!/bin/sh
# "Write each command to standard error (preceded by a ‘+ ’) before it is executed.  Useful for debugging"
set -x
#     Name:  rescuezilla
#  Purpose:  Perform appropriate startup of Rescuezilla executable rescuezillapy.
#
#            The purpose of these startup methods is to prevent
#            devices from being automounted, and to ensure only one
#            instance of Rescuezilla is running.  File system problems can
#            occur if devices are mounted prior to the completion of
#            Rescuezilla's operations, or if multiple partition editing
#            tools are in use concurrently.
#
# Copyright (C) 2008, 2009, 2010, 2013, 2015 Curtis Gedak
# Copyright (C) 2020 Rescuezilla.com <rescuezilla@gmail.com>
#
#  This file has been imported from the GParted project as it happens to be
#  perfectly suited for the Rescuezilla project
#
#  GParted is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  GParted is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with GParted.  If not, see <http://www.gnu.org/licenses/>.
#

# Helper function to run systemd as 'ubuntu' user, useful to mask out certain problematic systemd mount units.
# Mask the systemd mounts.To prevent "Failed to connect to bus: No such file or directory", adapted env variable from [1]
# [1]  https://askubuntu.com/a/1121053/394984
# FIXME: Re-evaluate this entire approach. It's currently sufficient for Rescuezilla's live environment, but definitely
# won't apply to all environments which Rescuezilla may run on.
run_systemctl_as_ubuntu() {
    CMD=$1
    UBUNTU_USER_XDG_RUNTIME_DIR="/run/user/999"
    UBUNTU_USER_DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
    XDG_RUNTIME_DIR="$UBUNTU_USER_XDG_RUNTIME_DIR" DBUS_SESSION_BUS_ADDRESS="$UBUNTU_USER_DBUS_SESSION_BUS_ADDRESS" su ubuntu -c "$CMD"
}

display_yad() {
    TITLE=$1
    MESSAGE=$2

    if test -x "/usr/bin/yad"; then
        yad --center \
            --title="$TITLE." \
            --button="OK:0" \
            --text "$MESSAGE"
        if [ "$?" -eq 0 ]; then
            exit 1
        fi
    fi
}

#
#  Define base command for executing Rescuezilla
#
BASE_CMD="/usr/sbin/rescuezillapy $*"

#
# Cannot launch Rescuezilla if GParted is already running.
#
if test "z`ps -e | grep gpartedbin`" != "z"; then
    MESSAGE="Cannot launch Rescuezilla because the process gpartedbin is running.\n\nClose GParted then try again."
    printf "$MESSAGE\n"
    display_yad "Rescuezilla" "$MESSAGE"
    exit 1
fi

#
#  Only permit one instance of Rescuezilla to execute at a time
#
if test "z`ps -e | grep rescuezillapy`" != "z"; then
    MESSAGE="The process rescuezillapy is already running.\n\nOnly one rescuezillapy process is permitted."
    printf "$MESSAGE\n"
    display_yad "Rescuezilla" "$MESSAGE"
    exit 1
fi

#
#  For non-root users try to get authorisation to run Rescuezilla as root.
#
if test "x`id -u`" != "x0"; then
    #
    #  If there is no configured SU program run rescuezillapy as
    #  non-root to display the graphical error about needing root
    #  privileges.
    #
        if test "xpkexec --disable-internal-agent" = "x"; then
        echo "Root privileges are required for running Rescuezilla."
        $BASE_CMD
        exit 1
    fi

    #
    # Interim workaround to allow Rescuezilla run by root access to the
    # X11 display server under Wayland.  If configured with
    # './configure --enable-xhost-root', the xhost command is
    # available and root has not been granted access to the X11
    # display via xhost, then grant access.
    #
    ENABLE_XHOST_ROOT=@enable_xhost_root@
    GRANTED_XHOST_ROOT=no
    if test "x$ENABLE_XHOST_ROOT" = 'xyes' && xhost 1> /dev/null 2>&1; then
        if ! xhost | grep -qi 'SI:localuser:root$'; then
            xhost +SI:localuser:root
            GRANTED_XHOST_ROOT=yes
        fi
    fi

    #
    # Run rescuezilla as root.
    #
    pkexec --disable-internal-agent '/usr/sbin/rescuezilla' "$@"
    status=$?

    #
    # Revoke root access to the X11 display, only if we granted it.
    #
    if test "x$GRANTED_XHOST_ROOT" = 'xyes'; then
        xhost -SI:localuser:root
    fi
    exit $status
fi

#
#  Search PATH to determine if systemctl program can be found
#  and if appropriate daemon is running.
#
HAVE_SYSTEMCTL=no
for k in '' `echo "$PATH" | sed 's,:, ,g'`; do
    if test -x "$k/systemctl"; then
        if test "z`ps -e | grep systemd`" != "z"; then
            HAVE_SYSTEMCTL=yes
            break
        fi
    fi
done

#
#  Check if udisks2-inhibit exists in known location
#  and if appropriate daemon is running.
#
HAVE_UDISKS2_INHIBIT=no
if test -x "/usr/lib/udisks2/udisks2-inhibit"; then
    if test "z`ps -e | grep 'udisksd'`" != "z"; then
        HAVE_UDISKS2_INHIBIT=yes
    fi
fi

#
#  Search PATH to determine if udisks program can be found
#  and if appropriate daemon is running.
#
HAVE_UDISKS=no
for k in '' `echo "$PATH" | sed 's,:, ,g'`; do
    if test -x "$k/udisks"; then
        if test "z`ps -e | grep udisks-daemon`" != "z"; then
            HAVE_UDISKS=yes
            break
        fi
    fi
done

#
#  Search PATH to determine if hal-lock program can be found
#  and if appropriate daemon is running.
#
HAVE_HAL_LOCK=no
for k in '' `echo "$PATH" | sed 's,:, ,g'`; do
    if test -x "$k/hal-lock"; then
        if test "z`ps -e | grep hald`" != "z"; then
            HAVE_HAL_LOCK=yes
            break
        fi
    fi
done

#
#  Use systemctl to prevent automount by masking currently unmasked mount points
#
if test "x$HAVE_SYSTEMCTL" = "xyes"; then
    MOUNTLIST=`systemctl list-units --full --all -t mount --no-legend \
      | grep -v masked | cut -f1 -d' ' \
      | egrep -v '^(dev-hugepages|dev-mqueue|proc-sys-fs-binfmt_misc|run-user-.*-gvfs|sys-fs-fuse-connections|sys-kernel-config|sys-kernel-debug)'`
    systemctl --runtime mask --quiet -- $MOUNTLIST

    # The Rescuezilla live environment has a user named 'ubuntu' with user ID 999. The existance of a GNOME Virtual Filesystem (GVFS) mount causes
    # Rescuezilla to fail on some restore operations, due to gvfs preventing the partition table from refreshing.
    UBUNTU_USER_MOUNTLIST=$( run_systemctl_as_ubuntu "systemctl --user list-units --full --all -t mount --no-legend \
      | grep -v masked | cut -f1 -d' ' \
      | egrep -v '^(dev-hugepages|dev-mqueue|proc-sys-fs-binfmt_misc|run-user-.*-gvfs|sys-fs-fuse-connections|sys-kernel-config|sys-kernel-debug)' | xargs")
    run_systemctl_as_ubuntu "systemctl --user --runtime mask --quiet -- $UBUNTU_USER_MOUNTLIST"
    # FIXME: Re-consider how to best handle GVFS
    #UBUNTU_USER_GVFS_MOUNTLIST=$( run_systemctl_as_ubuntu "systemctl --user list-units --full --all --no-legend | cut -f1 -d' ' | grep '^gvfs-' | xargs")
    #run_systemctl_as_ubuntu "systemctl --user --runtime mask --now --quiet -- $UBUNTU_USER_GVFS_MOUNTLIST"
fi

#
# Create temporary blank overrides for all udev rules which automatically
# start Linux Software RAID array members.
#
# Udev stores volatile / temporary runtime rules in directory /run/udev/rules.d.
# Older versions use /dev/.udev/rules.d instead, and even older versions don't
# have such a directory at all.  Volatile / temporary rules are use to override
# default rules from /lib/udev/rules.d.  (Permanent local administrative rules
# in directory /etc/udev/rules.d override all others).  See udev(7) manual page
# from various versions of udev for details.
#
# Default udev rules containing mdadm to incrementally start array members are
# found in 64-md-raid.rules and/or 65-md-incremental.rules, depending on the
# distribution and age.  The rules may be commented out or not exist at all.
#
UDEV_TEMP_MDADM_RULES=''  # List of temporary override rules files.
for udev_temp_d in /run/udev /dev/.udev; do
    if test -d "$udev_temp_d"; then
        test ! -d "$udev_temp_d/rules.d" && mkdir "$udev_temp_d/rules.d"
        udev_mdadm_rules=`egrep -l '^[^#].*mdadm (-I|--incremental)' /lib/udev/rules.d/*.rules 2> /dev/null`
        UDEV_TEMP_MDADM_RULES=`echo "$udev_mdadm_rules" | sed 's,^/lib/udev,'"$udev_temp_d"','`
        break
    fi
done
for rule in $UDEV_TEMP_MDADM_RULES; do
    touch "$rule"
done

#
#  Use udisks2-inhibit if udisks2-inhibit exists and deamon running.
#  Else use both udisks and hal-lock for invocation if both binaries exist and both
#  daemons are running.
#  Else use udisks if binary exists and daemon is running.
#  Otherwise use hal-lock for invocation if binary exists and daemon is running.
#  If the above checks fail then simply run rescuezillapy.
#
if test "x$HAVE_UDISKS2_INHIBIT" = "xyes"; then
    /usr/lib/udisks2/udisks2-inhibit $BASE_CMD
elif test "x$HAVE_UDISKS" = "xyes" && test "x$HAVE_HAL_LOCK" = "xyes"; then
    udisks --inhibit -- \
        hal-lock --interface org.freedesktop.Hal.Device.Storage --exclusive \
            --run "$BASE_CMD"
elif test "x$HAVE_UDISKS" = "xyes"; then
    udisks --inhibit -- $BASE_CMD
elif test "x$HAVE_HAL_LOCK" = "xyes"; then
    hal-lock --interface org.freedesktop.Hal.Device.Storage --exclusive \
        --run "$BASE_CMD"
else
    $BASE_CMD
fi

#
# Clear any temporary override udev rules used to stop udev automatically
# starting Linux Software RAID array members.
#
for rule in $UDEV_TEMP_MDADM_RULES; do
    rm -f "$rule"
done

#
#  Use systemctl to restore that status of any mount points changed above
#
if test "x$HAVE_SYSTEMCTL" = "xyes"; then
    systemctl --runtime unmask --quiet -- $MOUNTLIST
    run_systemctl_as_ubuntu "systemctl --user --runtime unmask --quiet -- $UBUNTU_USER_MOUNTLIST"
    #run_systemctl_as_ubuntu "systemctl --user --runtime unmask --quiet -- $UBUNTU_USER_GVFS_MOUNTLIST"
fi
