entrypoint.sh 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #!/bin/bash
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this
  4. # file, You can obtain one at https://mozilla.org/MPL/2.0/.
  5. set -e
  6. trap "echo TRAPed signal" HUP INT QUIT TERM
  7. # Wait for XDG_RUNTIME_DIR
  8. until [ -d "${XDG_RUNTIME_DIR}" ]; do sleep 0.5; done
  9. # Make user directory owned by the default ubuntu user
  10. chown -f ubuntu:ubuntu ~ || sudo-root chown -f ubuntu:ubuntu ~ || chown -R -f -h --no-preserve-root ubuntu:ubuntu ~ || sudo-root chown -R -f -h --no-preserve-root ubuntu:ubuntu ~ || echo 'Failed to change user directory permissions, there may be permission issues'
  11. # Change operating system password to environment variable
  12. (echo "$PASSWD"; echo "$PASSWD";) | sudo passwd ubuntu || (echo "mypasswd"; echo "$PASSWD"; echo "$PASSWD";) | passwd ubuntu || echo 'Password change failed, using default password'
  13. # Remove directories to make sure the desktop environment starts
  14. rm -rf /tmp/.X* ~/.cache || echo 'Failed to clean X11 paths'
  15. # Change time zone from environment variable
  16. ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | tee /etc/timezone > /dev/null || echo 'Failed to set timezone'
  17. # Add Lutris directories to path
  18. export PATH="${PATH:+${PATH}:}/usr/local/games:/usr/games"
  19. # Add LibreOffice to library path
  20. export LD_LIBRARY_PATH="/usr/lib/libreoffice/program${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
  21. # Configure joystick interposer
  22. export SELKIES_INTERPOSER='/usr/$LIB/selkies_joystick_interposer.so'
  23. export LD_PRELOAD="${SELKIES_INTERPOSER}${LD_PRELOAD:+:${LD_PRELOAD}}"
  24. export SDL_JOYSTICK_DEVICE=/dev/input/js0
  25. mkdir -pm777 /dev/input || sudo-root mkdir -pm777 /dev/input || echo 'Failed to create joystick interposer directory'
  26. touch /dev/input/js0 /dev/input/js1 /dev/input/js2 /dev/input/js3 || sudo-root touch /dev/input/js0 /dev/input/js1 /dev/input/js2 /dev/input/js3 || echo 'Failed to create joystick interposer devices'
  27. # Set default display
  28. export DISPLAY="${DISPLAY:-:20}"
  29. # PipeWire-Pulse server socket path
  30. export PIPEWIRE_LATENCY="128/48000"
  31. export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}"
  32. export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-/tmp}}"
  33. export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}"
  34. export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}/native}"
  35. if ! command -v nvidia-xconfig >/dev/null 2>&1; then
  36. # Install NVIDIA userspace driver components including X graphic libraries, keep contents same between docker-nvidia-glx-desktop and docker-nvidia-egl-desktop
  37. export NVIDIA_DRIVER_ARCH="$(dpkg --print-architecture | sed -e 's/arm64/aarch64/' -e 's/armhf/32bit-ARM/' -e 's/i.*86/x86/' -e 's/amd64/x86_64/' -e 's/unknown/x86_64/')"
  38. if [ -z "${NVIDIA_DRIVER_VERSION}" ]; then
  39. # Driver version is provided by the kernel through the container toolkit, prioritize kernel driver version if available
  40. if [ -f "/proc/driver/nvidia/version" ]; then
  41. export NVIDIA_DRIVER_VERSION="$(head -n1 </proc/driver/nvidia/version | awk '{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+\.[0-9\.]+/) {print $i; exit}}')"
  42. elif command -v nvidia-smi >/dev/null 2>&1; then
  43. # Use NVIDIA-SMI when not available
  44. export NVIDIA_DRIVER_VERSION="$(nvidia-smi --version | grep 'DRIVER version' | cut -d: -f2 | tr -d ' ')"
  45. else
  46. echo 'Failed to find NVIDIA GPU driver version, container will likely not start because of no NVIDIA container toolkit or NVIDIA GPU driver present'
  47. fi
  48. fi
  49. cd /tmp
  50. # If version is different, new installer will overwrite the existing components
  51. if [ ! -f "/tmp/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" ]; then
  52. # Check multiple sources in order to probe both consumer and datacenter driver versions
  53. curl -fsSL -O "https://international.download.nvidia.com/XFree86/Linux-${NVIDIA_DRIVER_ARCH}/${NVIDIA_DRIVER_VERSION}/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" || curl -fsSL -O "https://international.download.nvidia.com/tesla/${NVIDIA_DRIVER_VERSION}/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" || echo 'Failed NVIDIA GPU driver download'
  54. fi
  55. if [ -f "/tmp/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" ]; then
  56. # Extract installer before installing
  57. rm -rf "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}"
  58. sh "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" -x
  59. cd "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}"
  60. # Run NVIDIA driver installation without the kernel modules and host components
  61. sudo ./nvidia-installer --silent \
  62. --no-kernel-module \
  63. --install-compat32-libs \
  64. --no-nouveau-check \
  65. --no-nvidia-modprobe \
  66. --no-systemd \
  67. --no-rpms \
  68. --no-backup \
  69. --no-check-for-alternate-installs
  70. rm -rf /tmp/NVIDIA* && cd ~
  71. else
  72. echo 'Unless using non-NVIDIA GPUs, container will likely not work correctly'
  73. fi
  74. fi
  75. # Remove existing Xorg configuration
  76. if [ -f "/etc/X11/xorg.conf" ]; then
  77. rm -f "/etc/X11/xorg.conf"
  78. fi
  79. # Get first GPU device if all devices are available or `NVIDIA_VISIBLE_DEVICES` is not set
  80. if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ] || [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
  81. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  82. # Get first GPU device out of the visible devices in other situations
  83. else
  84. export GPU_SELECT="$(nvidia-smi --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid --format=csv,noheader | head -n1)"
  85. if [ -z "$GPU_SELECT" ]; then
  86. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  87. fi
  88. fi
  89. if [ -z "$GPU_SELECT" ]; then
  90. echo "No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Exiting."
  91. exit 1
  92. fi
  93. # Setting `VIDEO_PORT` to none disables RANDR/XRANDR, do not set this if using datacenter GPUs
  94. if [ "$(echo ${VIDEO_PORT} | tr '[:upper:]' '[:lower:]')" = "none" ]; then
  95. export CONNECTED_MONITOR="--use-display-device=None"
  96. # The X server is otherwise deliberately set to a specific video port despite not being plugged to enable RANDR/XRANDR, monitor will display the screen if plugged to the specific port
  97. else
  98. export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT}"
  99. fi
  100. # Bus ID from nvidia-smi is in hexadecimal format and should be converted to decimal format (including the domain) which Xorg understands, required because nvidia-xconfig doesn't work as intended in a container
  101. HEX_ID="$(nvidia-smi --query-gpu=pci.bus_id --id="$GPU_SELECT" --format=csv,noheader | head -n1)"
  102. IFS=":." ARR_ID=($HEX_ID)
  103. unset IFS
  104. BUS_ID="PCI:$((16#${ARR_ID[1]}))@$((16#${ARR_ID[0]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))"
  105. # A custom modeline should be generated because there is no monitor to fetch this information normally
  106. export MODELINE="$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n 2p)"
  107. # Generate /etc/X11/xorg.conf with nvidia-xconfig
  108. nvidia-xconfig --virtual="${DISPLAY_SIZEW}x${DISPLAY_SIZEH}" --depth="$DISPLAY_CDEPTH" --mode="$(echo "$MODELINE" | awk '{print $2; exit}' | tr -d '\"')" --allow-empty-initial-configuration --no-probe-all-gpus --busid="$BUS_ID" --include-implicit-metamodes --mode-debug --no-sli --no-base-mosaic --only-one-x-screen ${CONNECTED_MONITOR}
  109. # Guarantee that the X server starts without a monitor by adding more options to the configuration
  110. sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck,NoEdidMaxPClkCheck,NoMaxSizeCheck,NoHorizSyncCheck,NoVertRefreshCheck,NoVirtualSizeCheck,NoExtendedGpuCapabilitiesCheck,NoTotalSizeCheck,NoDualLinkDVICheck,NoDisplayPortBandwidthCheck,AllowNon3DVisionModes,AllowNonHDMI3DModes,AllowNonEdidModes,NoEdidHDMI2Check,AllowDpInterlaced"' /etc/X11/xorg.conf
  111. # Support external GPUs
  112. sed -i '/Driver\s\+"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
  113. # Add custom generated modeline to the configuration
  114. sed -i '/Section\s\+"Monitor"/a\ '"$MODELINE" /etc/X11/xorg.conf
  115. # Disable screen blanking in X11
  116. sed -i '/"DPMS"/d' /etc/X11/xorg.conf
  117. sed -i '/Section\s\+"Monitor"/a\ Option "DPMS" "False"' /etc/X11/xorg.conf
  118. # Prevent interference between GPUs, add this to the host or other containers running Xorg as well
  119. echo -e "Section \"ServerFlags\"\n Option \"DontVTSwitch\" \"True\"\n Option \"DontZap\" \"True\"\n Option \"AllowMouseOpenFail\" \"True\"\n Option \"AutoAddGPU\" \"False\"\nEndSection" | tee -a /etc/X11/xorg.conf > /dev/null
  120. # Run Xorg server with required extensions
  121. /usr/lib/xorg/Xorg "${DISPLAY}" vt7 -noreset -novtswitch -sharevts -nolisten "tcp" -ac -dpi "${DISPLAY_DPI}" +extension "COMPOSITE" +extension "DAMAGE" +extension "GLX" +extension "RANDR" +extension "RENDER" +extension "MIT-SHM" +extension "XFIXES" +extension "XTEST" &
  122. # Wait for X server to start
  123. echo 'Waiting for X Socket' && until [ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]; do sleep 0.5; done && echo 'X Server is ready'
  124. # Start KDE desktop environment
  125. export XDG_SESSION_ID="${DISPLAY#*:}"
  126. export QT_LOGGING_RULES="${QT_LOGGING_RULES:-*.debug=false;qt.qpa.*=false}"
  127. /usr/bin/dbus-launch --exit-with-session /usr/bin/startplasma-x11 &
  128. # Start Fcitx input method framework
  129. /usr/bin/fcitx &
  130. # Add custom processes right below this line, or within `supervisord.conf` to perform service management similar to systemd
  131. echo "Session Running. Press [Return] to exit."
  132. read