entrypoint.sh 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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 ubuntu:ubuntu /home/ubuntu || sudo-root chown ubuntu:ubuntu /home/ubuntu || chown ubuntu:ubuntu /home/ubuntu/* || sudo-root chown ubuntu:ubuntu /home/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
  13. # Remove directories to make sure the desktop environment starts
  14. rm -rf /tmp/.X* ~/.cache
  15. # Change time zone from environment variable
  16. ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | tee /etc/timezone > /dev/null
  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 SDL_JOYSTICK_DEVICE=/dev/input/js0
  23. mkdir -pm777 /dev/input || sudo-root mkdir -pm777 /dev/input || echo 'Failed to create joystick interposer directory'
  24. 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'
  25. # Set default display
  26. export DISPLAY="${DISPLAY:-:0}"
  27. # PipeWire-Pulse server socket location
  28. export PIPEWIRE_LATENCY="32/48000"
  29. export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}"
  30. export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-/tmp}}"
  31. export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}"
  32. export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}/native}"
  33. if ! command -v nvidia-xconfig >/dev/null 2>&1; then
  34. # Install NVIDIA userspace driver components including X graphic libraries, keep contents same between docker-nvidia-glx-desktop and docker-nvidia-egl-desktop
  35. 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/')"
  36. if [ -z "${NVIDIA_DRIVER_VERSION}" ]; then
  37. # Driver version is provided by the kernel through the container toolkit, prioritize kernel driver version if available
  38. if [ -f "/proc/driver/nvidia/version" ]; then
  39. 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}}')"
  40. elif command -v nvidia-smi >/dev/null 2>&1; then
  41. # Use NVIDIA-SMI when not available
  42. export NVIDIA_DRIVER_VERSION="$(nvidia-smi --version | grep 'DRIVER version' | cut -d: -f2 | tr -d ' ')"
  43. else
  44. echo 'Failed to find NVIDIA GPU driver version, container will likely not start because of no NVIDIA container toolkit or NVIDIA GPU driver present'
  45. fi
  46. fi
  47. cd /tmp
  48. # If version is different, new installer will overwrite the existing components
  49. if [ ! -f "/tmp/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" ]; then
  50. # Check multiple sources in order to probe both consumer and datacenter driver versions
  51. 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'
  52. fi
  53. if [ -f "/tmp/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" ]; then
  54. # Extract installer before installing
  55. sh "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" -x
  56. cd "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}"
  57. # Run NVIDIA driver installation without the kernel modules and host components
  58. sudo ./nvidia-installer --silent \
  59. --accept-license \
  60. --no-kernel-module \
  61. --install-compat32-libs \
  62. --no-nouveau-check \
  63. --no-nvidia-modprobe \
  64. --no-systemd \
  65. --no-rpms \
  66. --no-backup \
  67. --no-check-for-alternate-installs
  68. rm -rf /tmp/NVIDIA* && cd ~
  69. else
  70. echo 'Unless using non-NVIDIA GPUs, container will likely not work correctly'
  71. fi
  72. fi
  73. # Allow starting Xorg from a pseudoterminal instead of strictly on a tty console
  74. if [ ! -f /etc/X11/Xwrapper.config ]; then
  75. echo -e "allowed_users=anybody\nneeds_root_rights=yes" | tee /etc/X11/Xwrapper.config > /dev/null
  76. fi
  77. if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
  78. sed -i "s/allowed_users=console/allowed_users=anybody/;$ a needs_root_rights=yes" /etc/X11/Xwrapper.config
  79. fi
  80. # Remove existing Xorg configuration
  81. if [ -f "/etc/X11/xorg.conf" ]; then
  82. rm -f "/etc/X11/xorg.conf"
  83. fi
  84. # Get first GPU device if all devices are available or `NVIDIA_VISIBLE_DEVICES` is not set
  85. if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ] || [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
  86. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  87. # Get first GPU device out of the visible devices in other situations
  88. else
  89. export GPU_SELECT="$(nvidia-smi --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid --format=csv,noheader | head -n1)"
  90. if [ -z "$GPU_SELECT" ]; then
  91. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  92. fi
  93. fi
  94. if [ -z "$GPU_SELECT" ]; then
  95. echo "No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Exiting."
  96. exit 1
  97. fi
  98. # Setting `VIDEO_PORT` to none disables RANDR/XRANDR, do not set this if using datacenter GPUs
  99. if [ "$(echo ${VIDEO_PORT} | tr '[:upper:]' '[:lower:]')" = "none" ]; then
  100. export CONNECTED_MONITOR="--use-display-device=None"
  101. # 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
  102. else
  103. export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT}"
  104. fi
  105. # 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
  106. HEX_ID="$(nvidia-smi --query-gpu=pci.bus_id --id="$GPU_SELECT" --format=csv,noheader | head -n1)"
  107. IFS=":." ARR_ID=($HEX_ID)
  108. unset IFS
  109. BUS_ID="PCI:$((16#${ARR_ID[1]}))@$((16#${ARR_ID[0]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))"
  110. # A custom modeline should be generated because there is no monitor to fetch this information normally
  111. export MODELINE="$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n 2p)"
  112. # Generate /etc/X11/xorg.conf with nvidia-xconfig
  113. nvidia-xconfig --virtual="${DISPLAY_SIZEW}x${DISPLAY_SIZEH}" --depth="$DISPLAY_CDEPTH" --mode="$(echo "$MODELINE" | awk '{print $2}' | 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}
  114. # Guarantee that the X server starts without a monitor by adding more options to the configuration
  115. 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
  116. sed -i '/Driver\s\+"nvidia"/a\ Option "PrimaryGPU" "True"' /etc/X11/xorg.conf
  117. # Support external GPUs
  118. sed -i '/Driver\s\+"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
  119. # Add custom generated modeline to the configuration
  120. sed -i '/Section\s\+"Monitor"/a\ '"$MODELINE" /etc/X11/xorg.conf
  121. # Prevent interference between GPUs, add this to the host or other containers running Xorg as well
  122. echo -e "Section \"ServerFlags\"\n Option \"DontVTSwitch\" \"true\"\n Option \"AllowMouseOpenFail\" \"true\"\n Option \"AutoAddGPU\" \"false\"\nEndSection" | tee -a /etc/X11/xorg.conf > /dev/null
  123. # Real sudo (sudo-root) is required in Ubuntu 20.04 but not newer Ubuntu, this symbolic link enables running Xorg inside a container with `-sharevts`
  124. ln -snf /dev/ptmx /dev/tty7 || sudo-root ln -snf /dev/ptmx /dev/tty7 || echo 'Failed to create /dev/tty7 device'
  125. # Run Xorg server with required extensions
  126. /usr/bin/Xorg "${DISPLAY}" vt7 -noreset -novtswitch -sharevts -dpi "${DISPLAY_DPI}" +extension "COMPOSITE" +extension "DAMAGE" +extension "GLX" +extension "RANDR" +extension "RENDER" +extension "MIT-SHM" +extension "XFIXES" +extension "XTEST" &
  127. # Wait for X server to start
  128. echo 'Waiting for X Socket' && until [ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]; do sleep 0.5; done && echo 'X Server is ready'
  129. # Start KDE desktop environment
  130. export XDG_SESSION_ID="${DISPLAY#*:}"
  131. export QT_LOGGING_RULES='*.debug=false;qt.qpa.*=false'
  132. /usr/bin/startplasma-x11 &
  133. # Start Fcitx input method framework
  134. /usr/bin/fcitx &
  135. # Add custom processes right below this line, or within `supervisord.conf` to perform service management similar to systemd
  136. echo "Session Running. Press [Return] to exit."
  137. read