#!/usr/bin/env bash

# Copyright (C) 2023-2025 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
#
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.

root="$1"
username="${USER}"

usage()
{
    echo "Usage: $0 [-u <user> ] <path/to/rootfs>"
    exit 1
}

bind_mount()
{
    src="$1"
    dst="$2"

    if [ -f "${src}" ] && [ ! -f "${dst}" ] ; then
	sudo mkdir -p "$(dirname "${dst}")"
	sudo touch "${dst}"
    elif [ -d "${src}" ] && [ ! -d "${dst}" ] ; then
	sudo mkdir -p "${dst}"
    fi

    sudo mount --rbind "${src}" "${dst}"
}

if [ $# -eq 3 ] && [ "$1" = "-u" ] ; then
    username="$2"
    root="$3"
elif [ $# -ne 1 ] ; then
    usage
fi

# The host PATH might differ from the target PATH, and we want to be
# able to chroot from an FHS distribution in a non-FHS one and
# vice-versa. Finding the mount binary path is also easier than trying
# to write code that can set the PATH accross a wide variety of
# distributions. For instance Trisquel uses /etc/environment to set
# the PATH, but for PureOS it is not done there and I've no idea where
# it is set.
mount=""
if [ -f "${root}"/bin/mount ] ; then
    # FHS distributions
    mount="/bin/mount"
elif [ -f /run/privileged/bin/mount ] ; then
    # First choice in the PATH when using Guix
    mount="/run/privileged/bin/mount"
elif [ -f /run/current-system/profile/bin/mount ] ; then
    # Second choice in the PATH when using Guix
    mount="/run/current-system/profile/bin/mount"
else
    # This will only work if the host PATH is compatible with the
    # target PATH.
    mount="mount"
fi

sudo chroot "${root}" "${mount}" "-o" "bind" "/" "/"

for d in dev etc/machine-id etc/resolv.conf proc sys tmp/.X11-unix ; do
    sudo mount | \
        grep " on ${root}/$d" > /dev/null || \
        bind_mount /"$d" "${root}"/"$d"
done

sudo chroot "${root}" "${mount}" "-a"

if [ -f "${XAUTHORITY}" ] ; then
    sudo mount | grep " on ${root}/${XAUTHORITY}" > /dev/null || \
        bind_mount "${XAUTHORITY}" "${root}"/"${XAUTHORITY}"
fi

# shellcheck disable=SC1090 disable=SC1091
. "${root}"/etc/os-release

if [ "${ID}" = "guix" ] ; then
    # We don't use sudo because otherwise we end up with the following
    # error:
    #     sudo: pam_open_session: Error in service module
    #     sudo: policy plugin failed session initialization
    #
    # And we don't use su either because it also fails with the following
    # error:
    #     su: Error in service module
    #
    # So in pratcice for now this means that we only have the root
    # user available
    sudo chroot "${root}" /bin/sh -c \
         "XAUTHORITY=\"${XAUTHORITY}\" \
         DISPLAY=\"${DISPLAY}\" \
         WAYLAND_DISPLAY=\"${WAYLAND_DISPLAY}\" \
         . /var/guix/profiles/system/profile/etc/profile ; \
         . \"${HOME}\"/.guix-profile/etc/profile ; \
         . \"${HOME}\"/.config/guix/current/etc/profile ; \
         bash"
else
    sudo chroot "${root}" /bin/bash --login -c \
         "/usr/bin/sudo \
         XAUTHORITY=\"${XAUTHORITY}\" \
         DISPLAY=\"${DISPLAY}\" \
         WAYLAND_DISPLAY=\"${WAYLAND_DISPLAY}\" \
         -i -u \"${username}\""
fi
