Files
netris-nestri/packages/scripts/entrypoint.sh
DatCaptainHorse b743dab332 fix: Fix good chunk of packet loss and frame drop issues
- Also added new latency control parameter, not super visible differences, but it's cool :)
2025-12-04 02:21:46 +02:00

371 lines
12 KiB
Bash

#!/bin/bash
set -euo pipefail
# Common helpers as requirement
if [[ -f /etc/nestri/common.sh ]]; then
source /etc/nestri/common.sh
else
echo "Error: Common script not found at /etc/nestri/common.sh" >&2
exit 1
fi
# Configuration
CACHE_DIR="${NESTRI_HOME}/.cache/nestri"
NVIDIA_INSTALLER_DIR="/tmp"
TIMEOUT_SECONDS=10
ENTCMD_PREFIX=""
# Ensures user ownership across directories
handle_user_permissions() {
if ! $ENTCMD_PREFIX chown "${NESTRI_USER}:${NESTRI_USER}" "${NESTRI_HOME}" 2>/dev/null; then
echo "Error: Failed to change ownership of ${NESTRI_HOME} to ${NESTRI_USER}:${NESTRI_USER}" >&2
return 1
fi
# Also apply to .cache
if [[ -d "${NESTRI_HOME}/.cache" ]]; then
if ! $ENTCMD_PREFIX chown "${NESTRI_USER}:${NESTRI_USER}" "${NESTRI_HOME}/.cache" 2>/dev/null; then
echo "Error: Failed to change ownership of ${NESTRI_HOME}/.cache to ${NESTRI_USER}:${NESTRI_USER}" >&2
return 1
fi
fi
return 0
}
# Waits for a given socket to be ready
wait_for_socket() {
local socket_path="$1"
local name="$2"
log "Waiting for $name socket at $socket_path..."
for ((i=1; i<=TIMEOUT_SECONDS; i++)); do
if [[ -e "$socket_path" ]]; then
log "$name socket is ready."
return 0
fi
sleep 1
done
log "Error: $name socket did not appear after ${TIMEOUT_SECONDS}s."
return 1
}
# Prepares environment for namespace-less applications (like Steam)
setup_namespaceless() {
$ENTCMD_PREFIX rm -f /run/systemd/container || true
$ENTCMD_PREFIX mkdir -p /run/pressure-vessel || true
}
# Ensures cache directory exists
setup_cache() {
log "Setting up cache directory at $CACHE_DIR..."
mkdir -p "$CACHE_DIR" || {
log "Warning: Failed to create cache directory, continuing.."
return 1
}
$ENTCMD_PREFIX chown "${NESTRI_USER}:${NESTRI_USER}" "$CACHE_DIR" 2>/dev/null || {
log "Warning: Failed to set cache directory ownership, continuing.."
}
}
# Grabs NVIDIA driver installer
get_nvidia_installer() {
local driver_version="$1"
local arch="$2"
local filename="NVIDIA-Linux-${arch}-${driver_version}.run"
local cached_file="${CACHE_DIR}/${filename}"
local tmp_file="${NVIDIA_INSTALLER_DIR}/${filename}"
# Check cache
if [[ -f "$cached_file" ]]; then
log "Found cached NVIDIA installer at $cached_file."
cp "$cached_file" "$tmp_file" || {
log "Warning: Failed to copy cached installer, proceeding with download."
rm -f "$cached_file" 2>/dev/null
}
fi
# Download if not in tmp
if [[ ! -f "$tmp_file" ]]; then
log "Downloading NVIDIA driver installer ($filename)..."
local urls=(
"https://international.download.nvidia.com/XFree86/Linux-${arch}/${driver_version}/${filename}"
"https://international.download.nvidia.com/tesla/${driver_version}/${filename}"
)
local success=0
for url in "${urls[@]}"; do
if wget -q --show-progress "$url" -O "$tmp_file"; then
success=1
break
fi
log "Failed to download from $url, trying next source..."
done
if [[ "$success" -eq 0 ]]; then
log "Error: Failed to download NVIDIA driver from all sources."
return 1
fi
# Cache the downloaded file
cp "$tmp_file" "$cached_file" 2>/dev/null && \
$ENTCMD_PREFIX chown "${NESTRI_USER}:${NESTRI_USER}" "$cached_file" 2>/dev/null || \
log "Warning: Failed to cache NVIDIA driver, continuing..."
fi
chmod +x "$tmp_file" || {
log "Error: Failed to make NVIDIA installer executable."
return 1
}
return 0
}
# Installs the NVIDIA driver
install_nvidia_driver() {
local filename="$1"
log "Installing NVIDIA driver components from $filename..."
$ENTCMD_PREFIX bash ./"$filename" \
--silent \
--skip-depmod \
--skip-module-unload \
--no-kernel-module \
--install-compat32-libs \
--no-nouveau-check \
--no-nvidia-modprobe \
--no-systemd \
--no-rpms \
--no-backup \
--no-distro-scripts \
--no-libglx-indirect \
--no-install-libglvnd \
--no-check-for-alternate-installs || {
log "Error: NVIDIA driver installation failed."
return 1
}
log "NVIDIA driver installation completed."
return 0
}
log_container_info() {
if ! declare -p container_runtime &>/dev/null; then
log "Warning: container_runtime is not defined"
return
fi
if [[ "${container_runtime:-none}" != "none" ]]; then
log "Detected container:"
log "> ${container_runtime}"
else
log "No container runtime detected"
fi
}
log_gpu_info() {
if ! declare -p vendor_devices &>/dev/null; then
log "Warning: vendor_devices array is not defined"
return
fi
log "Detected GPUs:"
for vendor in "${!vendor_devices[@]}"; do
log "> $vendor: ${vendor_devices[$vendor]}"
done
}
configure_ssh() {
# Return early if SSH not enabled
if [ -z "${SSH_ENABLE_PORT+x}" ] || [ "${SSH_ENABLE_PORT:-0}" -eq 0 ]; then
return 0
fi
# Check if we have required key
if [ -z "${SSH_ALLOWED_KEY+x}" ] || [ -z "${SSH_ALLOWED_KEY}" ]; then
return 0
fi
log "Configuring SSH server on port ${SSH_ENABLE_PORT} with public key authentication"
# Ensure SSH host keys exist
$ENTCMD_PREFIX ssh-keygen -A 2>/dev/null || {
log "Error: Failed to generate SSH host keys"
return 1
}
# Create .ssh directory and authorized_keys file for nestri user
mkdir -p "${NESTRI_HOME}/.ssh"
echo "${SSH_ALLOWED_KEY}" > "${NESTRI_HOME}/.ssh/authorized_keys"
chmod 700 "${NESTRI_HOME}/.ssh"
chmod 600 "${NESTRI_HOME}/.ssh/authorized_keys"
chown -R "${NESTRI_USER}:${NESTRI_USER}" "${NESTRI_HOME}/.ssh"
# Configure secure SSH settings
{
echo "PasswordAuthentication no"
echo "PermitRootLogin no"
echo "ChallengeResponseAuthentication no"
echo "UsePAM no"
echo "PubkeyAuthentication yes"
} | while read -r line; do
if ! grep -qF "$line" /etc/ssh/sshd_config; then
printf '%s\n' "$line" | $ENTCMD_PREFIX tee -a /etc/ssh/sshd_config >/dev/null
fi
done
# Start SSH server
log "Starting SSH server on port ${SSH_ENABLE_PORT}"
$ENTCMD_PREFIX /usr/sbin/sshd -D -p "${SSH_ENABLE_PORT}" &
SSH_PID=$!
# Verify the process started
if ! ps -p $SSH_PID > /dev/null 2>&1; then
log "Error: SSH server failed to start"
return 1
fi
log "SSH server started with PID ${SSH_PID}"
return 0
}
main() {
# Wait for required sockets
wait_for_socket "${NESTRI_XDG_RUNTIME_DIR}/dbus-1" "DBus" || exit 1
wait_for_socket "${NESTRI_XDG_RUNTIME_DIR}/pipewire-0" "PipeWire" || exit 1
# Start by getting the container we are running under
get_container_info || {
log "Warning: Failed to detect container information"
}
log_container_info
if [[ "$container_runtime" != "apptainer" ]]; then
ENTCMD_PREFIX="sudo -E"
fi
# Setup cache now
setup_cache
# Configure SSH
if [ -n "${SSH_ENABLE_PORT+x}" ] && [ "${SSH_ENABLE_PORT:-0}" -ne 0 ] && \
[ -n "${SSH_ALLOWED_KEY+x}" ] && [ -n "${SSH_ALLOWED_KEY}" ]; then
if ! configure_ssh; then
log "Error: SSH configuration failed with given variables - exiting"
exit 1
fi
else
log "SSH not configured (missing SSH_ENABLE_PORT or SSH_ALLOWED_KEY)"
fi
# Get and detect GPU(s)
get_gpu_info || {
log "Error: Failed to detect GPU information"
exit 1
}
log_gpu_info
# Handle NVIDIA GPU
if [[ -n "${vendor_devices[nvidia]:-}" ]]; then
log "NVIDIA GPU(s) detected, applying driver fix.."
# Determine NVIDIA driver version
local nvidia_driver_version=""
if [[ -f "/proc/driver/nvidia/version" ]]; then
nvidia_driver_version=$(awk '/NVIDIA/ {for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+\.[0-9\.]+/) {print $i; exit}}' /proc/driver/nvidia/version | head -n1)
elif command -v nvidia-smi >/dev/null 2>&1; then
nvidia_driver_version=$(nvidia-smi --version | grep -i 'driver version' | cut -d: -f2 | tr -d ' ')
fi
if [[ -z "$nvidia_driver_version" ]]; then
log "Error: Failed to determine NVIDIA driver version."
# Check for other GPU vendors before exiting
if [[ -n "${vendor_devices[amd]:-}" || -n "${vendor_devices[intel]:-}" ]]; then
log "Other GPUs (AMD or Intel) detected, continuing without NVIDIA driver"
else
log "No other GPUs detected, exiting due to NVIDIA driver version failure"
exit 1
fi
else
log "Detected NVIDIA driver version: $nvidia_driver_version"
# Get installer
local arch=$(uname -m)
local filename="NVIDIA-Linux-${arch}-${nvidia_driver_version}.run"
cd "$NVIDIA_INSTALLER_DIR" || {
log "Error: Failed to change to $NVIDIA_INSTALLER_DIR."
exit 1
}
get_nvidia_installer "$nvidia_driver_version" "$arch" || {
# Check for other GPU vendors before exiting
if [[ -n "${vendor_devices[amd]:-}" || -n "${vendor_devices[intel]:-}" ]]; then
log "Other GPUs (AMD or Intel) detected, continuing without NVIDIA driver"
else
log "No other GPUs detected, exiting due to NVIDIA installer failure"
exit 1
fi
}
# Install driver
install_nvidia_driver "$filename" || {
# Check for other GPU vendors before exiting
if [[ -n "${vendor_devices[amd]:-}" || -n "${vendor_devices[intel]:-}" ]]; then
log "Other GPUs (AMD or Intel) detected, continuing without NVIDIA driver"
else
log "No other GPUs detected, exiting due to NVIDIA driver installation failure"
exit 1
fi
}
fi
fi
# Make sure gamescope has CAP_SYS_NICE capabilities if available
log "Checking for CAP_SYS_NICE availability.."
if capsh --print | grep -q "Current:.*cap_sys_nice"; then
log "Giving gamescope compositor CAP_SYS_NICE permissions.."
setcap 'CAP_SYS_NICE+eip' /usr/bin/gamescope 2>/dev/null || {
log "Warning: Failed to set CAP_SYS_NICE on gamescope, continuing without it.."
}
else
log "Skipping CAP_SYS_NICE for gamescope, capability not available"
fi
# Make sure /tmp/.X11-unix exists..
if [[ ! -d "/tmp/.X11-unix" ]]; then
log "Creating /tmp/.X11-unix directory.."
$ENTCMD_PREFIX mkdir -p /tmp/.X11-unix || {
log "Error: Failed to create /tmp/.X11-unix directory"
exit 1
}
# Set required perms..
$ENTCMD_PREFIX chmod 1777 /tmp/.X11-unix || {
log "Error: Failed to chmod /tmp/.X11-unix to 1777"
exit 1
}
fi
# Handle user permissions
log "Ensuring user permissions..."
handle_user_permissions || exit 1
# Setup namespaceless env if needed for container runtime
if [[ "$container_runtime" != "podman" ]]; then
log "Applying namespace-less configuration"
setup_namespaceless
fi
# Wait for vimputti socket before switching to application startup
wait_for_socket "/tmp/vimputti-0" "vimputti" || exit 1
# Switch to nestri runner entrypoint
log "Switching to application startup entrypoint..."
if [[ ! -f /etc/nestri/entrypoint_nestri.sh ]]; then
log "Error: Application entrypoint script /etc/nestri/entrypoint_nestri.sh not found"
exit 1
fi
if [[ "$container_runtime" == "apptainer" ]]; then
exec /etc/nestri/entrypoint_nestri.sh
else
exec sudo -E -u "${NESTRI_USER}" /etc/nestri/entrypoint_nestri.sh
fi
}
# Trap signals for clean exit
trap 'log "Received termination signal, exiting.."; exit 0' SIGINT SIGTERM
main