#!/bin/bash
set -e
if [ "`id -u`" != 0 ]; then
    echo "Error: this test suite wrapper needs to be called as root" >&2
    exit 1
fi

if ! type smbd >/dev/null 2>&1; then
    echo "Error: this test suite wrapper needs samba installed" >&2
    exit 1
fi

# find out the user who calls us
pid=$$
while [ "`stat -c '%u' /proc/$pid`" = "0" ]; do
    pid=`awk '/^PPid:/ {print $2}' /proc/$pid/status`
    if [ -z "$pid" -o "$pid" = "1" ]; then
        echo "Error: Did not find a parent process that runs as non-root" >&2
        exit 1
    fi
done
CALLING_UID="`stat -c '%u' /proc/$pid`"
CALLING_USER="`stat -c '%U' /proc/$pid`"

# sanity check
[ "$CALLING_UID" -gt 0 ] && [ -n "$CALLING_USER" ]
CALLING_GROUP="`id -gn $CALLING_USER`"

# find udisks daemon
UDISKSD=`sed -n '/^Exec=/ { s/^[^=]*=//; p }' /usr/share/dbus-1/system-services/*UDisks2*.service | cut -f1 -d' '`
if [ ! -x "$UDISKSD" ]; then
    echo "Error: Did not find udisksd path" >&2
    exit 1
fi

# smbd needs to be restarted in the sandbox
service smbd stop && smbd_running=1 || :
service nmbd stop && nmbd_running=1 || :

MNT=`mktemp -d`

# work around scsi_debug not implementing CD-ROM SCSI commands
# see https://launchpad.net/bugs/1043182 for details
if [ -d /run/udev/rules.d/ -a ! -e /run/udev/rules.d/60-persistent-storage-scsi_debug.rules ]; then
    cat <<EOF > /run/udev/rules.d/60-persistent-storage-scsi_debug.rules
KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ATTRS{model}=="scsi_debug*", ENV{ID_CDROM_MEDIA}=="?*", IMPORT{program}="/sbin/blkid -o udev -p -u noraid \$tempnode"
EOF
    sync
    pkill --signal HUP udevd || pkill --signal HUP systemd-udevd
fi

# prevent nautilus popups for temporary drives in running sessions
pkill --signal STOP -f gvfs-udisks2-volume-monitor || :

cat <<EOF | unshare -m sh
set -e
mount -n -t tmpfs tmpfs $MNT

# prepare overlay directories and copy essential configuration
mkdir -p $MNT/etc/ssh $MNT/etc/ssl $MNT/var/lib $MNT/var/cache/samba $MNT/var/log/samba $MNT/home/$CALLING_USER $MNT/run_samba $MNT/media
touch $MNT/etc/fstab $MNT/home/gvfs_sandbox_marker
cp -a /etc/passwd /etc/shadow /etc/group /etc/hosts /etc/samba /etc/pam* /etc/init /etc/init.d /etc/systemd /etc/login.defs /etc/dbus-1 /etc/polkit-1 $MNT/etc/
cp /etc/ssh/sshd_config $MNT/etc/ssh/
cp /etc/ssl/*.cnf $MNT/etc/ssl/
cp -a /var/lib/samba $MNT/var/lib
touch $MNT/var/log/sshd.log
chown $CALLING_USER:$CALLING_GROUP $MNT/home/$CALLING_USER $MNT/var/log/sshd.log

# copy our local mock polkitd into testbed
cp `dirname $0`/test_polkitd.py $MNT/home/

# Debianisms
if [ -d /etc/alternatives ]; then
    cp -a /etc/alternatives $MNT/etc/
fi
if [ -L /var/run ]; then
    cp -a /var/run $MNT/var
fi

# if we run a script, we need to copy it into the sandbox as it might be in
# a directory that we overlay
if [ -f "$1" ]; then
    cp -a "$1" $MNT/home/gvfs-testbed-script
    ARGS="/home/gvfs-testbed-script ${@:2}"
else
    ARGS="$@"
fi

# realize our overlays
mount -n --bind $MNT/etc/ /etc/
mount --bind $MNT/home/ /home/
mount --bind $MNT/var/ /var/
mount --bind $MNT/media/ /media
mount --bind $MNT/run_samba/ /run/samba

# generate ssh host keys, and make them world readable, so that sshd can be
# started as user
ssh-keygen -A
chmod o+r /etc/ssh/*

# ensure that the calling user can define Samba usershares
usershare_group=`stat -c '%G' /var/lib/samba/usershare*`
usermod -a -G \$usershare_group $CALLING_USER

# run Samba with local configuration/state
nmbd -D -l /var/log/samba
smbd -D -l /var/log/samba

# we need a predictable password for the smb:// authenticated test, so change
# it to "foo" in the sandbox
/bin/echo -e 'foo\\nfoo\\n' | smbpasswd -a $CALLING_USER -s

# create a root shell that the user can call to control scsi_debug and
# similar
cp /bin/sh /home/$CALLING_USER/rootsh
chown root:$CALLING_USER /home/$CALLING_USER/rootsh
chmod 4550 /home/$CALLING_USER/rootsh

# we must start udisksd in our private mount environment, so that gvfs and
# udisks agree to the same view of mounts
$UDISKSD --no-debug --replace &
UDISKS_PID=\$!

echo "Running commmand in testbed: \$ARGS"
su -lc "export PATH=$PATH export SSHD=`which sshd`; export \\\`dbus-launch\\\`; \$ARGS; rc=\\\$?; kill \\\$DBUS_SESSION_BUS_PID; exit \\\$rc" $CALLING_USER || {
    RC=\$?
    echo "=== command failed, showing Samba log files ==="
    for f in /var/log/samba/log.*; do
        echo "--- \$f ---"
        cat \$f
    done
    if [ -e /var/log/sshd.log ]; then
        echo "=== sshd log file ==="
        cat /var/log/sshd.log
    fi
}
cat /var/run/samba/*.pid | xargs kill
kill \$UDISKS_PID || :
exit \$RC
EOF
RC=$?

pkill --signal CONT -f gvfs-udisks2-volume-monitor || :

[ -n "$smbd_running" ] && service smbd start || :
[ -n "$nmbd_running" ] && service nmbd start || :

rmdir "$MNT" || :
exit $RC
