Full Bash script from Filebin URL above:
#!/bin/bash
set -o nounset
set -o pipefail
UNIT_NAME='vbox-wayland-clipboard.service'
UNIT_PATH='/usr/lib/systemd/user/vbox-wayland-clipboard.service'
LAUNCH_PATH='/usr/libexec/vm-config-dist/vbox-wayland-clipboard-autostart'
DESK_PATH='/etc/xdg/autostart/vbox-wayland-clipboard.desktop'
red() { printf '\033[31m%s\033[0m\n' "$*"; }
grn() { printf '\033[32m%s\033[0m\n' "$*"; }
ylw() { printf '\033[33m%s\033[0m\n' "$*"; }
if [ "$(id -u)" -ne 0 ]; then
red "ERROR: run as root in the 'sysmaint' boot mode: sudo bash $0"
exit 1
fi
search_dirs=(/etc/systemd/user /run/systemd/user /usr/lib/systemd/user \
/usr/local/lib/systemd/user /root/.config/systemd/user)
for h in /home/*; do
[ -d "$h/.config/systemd/user" ] && search_dirs+=("$h/.config/systemd/user")
done
echo "=== INSTALL ==="
echo "[1/6] clearing masks (/dev/null symlinks) and empty unit files ..."
for d in "${search_dirs[@]}"; do
f="$d/$UNIT_NAME"
if [ -L "$f" ] || { [ -e "$f" ] && [ ! -s "$f" ]; }; then
echo " removing $f"
rm -f "$f"
fi
done
systemctl --global unmask "$UNIT_NAME" 2>/dev/null || true
echo "[2/6] writing $UNIT_PATH ..."
install -d /usr/lib/systemd/user
cat > "$UNIT_PATH" <<'UNIT'
[Unit]
Description=VirtualBox shared clipboard for Wayland (opt-in, default-off)
ConditionVirtualization=oracle
ConditionEnvironment=WAYLAND_DISPLAY
StartLimitIntervalSec=10
StartLimitBurst=3
[Service]
Type=simple
ExecStart=/usr/bin/VBoxClient --foreground --wayland
Restart=on-failure
RestartSec=2s
[Install]
WantedBy=default.target
UNIT
echo "[3/6] writing $LAUNCH_PATH ..."
install -d /usr/libexec/vm-config-dist
cat > "$LAUNCH_PATH" <<'LAUNCH'
#!/bin/bash
set -o nounset
set -o pipefail
PATH=/usr/bin:/bin
unit='vbox-wayland-clipboard.service'
state="$(systemctl --user is-enabled "$unit" 2>/dev/null || true)"
case "$state" in
enabled|enabled-runtime) ;;
*) exit 0 ;;
esac
counter=0
while [ "$counter" -lt 50 ]; do
systemctl --user show-environment 2>/dev/null | grep -q '^WAYLAND_DISPLAY=' && break
counter="$(( counter + 1 ))"
sleep 0.2
done
systemctl --user reset-failed "$unit" 2>/dev/null || true
exec systemctl --user start "$unit"
LAUNCH
chmod 755 "$LAUNCH_PATH"
echo "[4/6] writing $DESK_PATH ..."
cat > "$DESK_PATH" <<'DESK'
[Desktop Entry]
Type=Application
Name=VirtualBox shared clipboard for Wayland (opt-in)
Exec=/usr/libexec/vm-config-dist/vbox-wayland-clipboard-autostart
StartupNotify=false
NoDisplay=true
NotShowIn=QUBES;
DESK
echo "[5/6] Guest Additions device (/dev/vboxuser) on every boot ..."
systemctl enable --now virtualbox-guest-utils.service 2>/dev/null \
|| ylw " virtualbox-guest-utils.service not found; loading module only."
echo vboxguest > /etc/modules-load.d/vboxguest.conf
modprobe vboxguest 2>/dev/null || true
echo "[6/6] enabling for ALL users ..."
systemctl daemon-reload
systemctl --global enable "$UNIT_NAME"
echo
echo "=== CHECKUP ==="
fail=0; warn=0
chk_file() {
local p="$1" min="$2" sz
if [ -L "$p" ]; then red " FAIL $p is a symlink (masked?)"; fail=$((fail+1)); return; fi
if [ ! -f "$p" ]; then red " FAIL $p missing"; fail=$((fail+1)); return; fi
sz="$(wc -c < "$p")"
if [ "$sz" -lt "$min" ]; then red " FAIL $p is $sz bytes (empty/too small)"; fail=$((fail+1)); return; fi
grn " OK $p ($sz bytes)"
}
chk_file "$UNIT_PATH" 100
chk_file "$LAUNCH_PATH" 100
chk_file "$DESK_PATH" 50
leftover=0
for d in "${search_dirs[@]}"; do
f="$d/$UNIT_NAME"
[ "$f" = "$UNIT_PATH" ] && continue
if [ -L "$f" ] || { [ -e "$f" ] && [ ! -s "$f" ]; }; then
red " FAIL leftover mask/empty: $f"; leftover=$((leftover+1)); fail=$((fail+1))
fi
done
[ "$leftover" -eq 0 ] && grn " OK no leftover masks / empty unit files"
if [ -x "$LAUNCH_PATH" ]; then grn " OK launcher is executable"; else red " FAIL launcher not executable"; fail=$((fail+1)); fi
if [ -L "/etc/systemd/user/default.target.wants/$UNIT_NAME" ]; then
grn " OK enabled for all users (default.target.wants symlink present)"
else
ylw " WARN global enable symlink missing"; warn=$((warn+1))
fi
if command -v VBoxClient >/dev/null 2>&1; then
grn " OK VBoxClient present ($(VBoxClient --version 2>/dev/null | head -n1))"
else
red " FAIL /usr/bin/VBoxClient not found (Guest Additions missing)"; fail=$((fail+1))
fi
if lsmod 2>/dev/null | grep -q '^vboxguest'; then grn " OK vboxguest module loaded"; else ylw " WARN vboxguest module not loaded"; warn=$((warn+1)); fi
if [ -e /dev/vboxuser ]; then grn " OK /dev/vboxuser present"; else red " FAIL /dev/vboxuser missing (VBoxClient will fail VbglR3InitUser)"; fail=$((fail+1)); fi
echo
if [ "$fail" -eq 0 ]; then grn "RESULT: install OK ($warn warning(s))."; else red "RESULT: $fail problem(s), $warn warning(s) — fix the FAIL lines above."; fi
echo
echo "NEXT:"
echo " 1) On the HOST (normal user, VM powered off):"
echo " VBoxManage modifyvm \"<vm-name-or-uuid>\" --clipboard-mode bidirectional"
echo " and launch the VM as your NORMAL user, not root."
echo " 2) Reboot Whonix into the normal 'user' mode."
echo " 3) As 'user' (no sudo) verify:"
echo " systemctl --user is-enabled $UNIT_NAME # => enabled (NOT masked)"
echo " systemctl --user status $UNIT_NAME # => active (running)"
[ "$fail" -eq 0 ] && exit 0 || exit 1