entrypoint.sh 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. # Create and modify permissions of XDG_RUNTIME_DIR
  8. mkdir -pm700 /tmp/runtime-ubuntu
  9. chown ubuntu:ubuntu /tmp/runtime-ubuntu
  10. chmod 700 /tmp/runtime-ubuntu
  11. # Make user directory owned by the default ubuntu user
  12. 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'
  13. # Change operating system password to environment variable
  14. (echo "$PASSWD"; echo "$PASSWD";) | sudo passwd ubuntu
  15. # Remove directories to make sure the desktop environment starts
  16. rm -rf /tmp/.X* ~/.cache
  17. # Change time zone from environment variable
  18. ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | tee /etc/timezone > /dev/null
  19. # Add Lutris directories to path
  20. export PATH="${PATH:+${PATH}:}/usr/local/games:/usr/games"
  21. # Add LibreOffice to library path
  22. export LD_LIBRARY_PATH="/usr/lib/libreoffice/program${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
  23. # Configure joystick interposer
  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:-:0}"
  29. # PipeWire-Pulse server socket location
  30. export PIPEWIRE_LATENCY="32/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 as 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. You might not be using the NVIDIA container toolkit. Exiting."
  47. exit 1
  48. fi
  49. fi
  50. cd /tmp
  51. # If version is different, new installer will overwrite the existing components
  52. if [ ! -f "/tmp/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" ]; then
  53. # Check multiple sources in order to probe both consumer and datacenter driver versions
  54. 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. Exiting."; exit 1; }
  55. fi
  56. # Extract installer before installing
  57. sh "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" -x
  58. cd "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}"
  59. # Run NVIDIA driver installation without the kernel modules and host components
  60. sudo ./nvidia-installer --silent \
  61. --accept-license \
  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. fi
  72. # Allow starting Xorg from a pseudoterminal instead of strictly on a tty console
  73. if [ ! -f /etc/X11/Xwrapper.config ]; then
  74. echo -e "allowed_users=anybody\nneeds_root_rights=yes" | tee /etc/X11/Xwrapper.config > /dev/null
  75. fi
  76. if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
  77. sed -i "s/allowed_users=console/allowed_users=anybody/;$ a needs_root_rights=yes" /etc/X11/Xwrapper.config
  78. fi
  79. # Remove existing Xorg configuration
  80. if [ -f "/etc/X11/xorg.conf" ]; then
  81. rm -f "/etc/X11/xorg.conf"
  82. fi
  83. # Get first GPU device if all devices are available or `NVIDIA_VISIBLE_DEVICES` is not set
  84. if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ] || [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
  85. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  86. # Get first GPU device out of the visible devices in other situations
  87. else
  88. export GPU_SELECT="$(nvidia-smi --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid --format=csv,noheader | head -n1)"
  89. if [ -z "$GPU_SELECT" ]; then
  90. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  91. fi
  92. fi
  93. if [ -z "$GPU_SELECT" ]; then
  94. echo "No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Exiting."
  95. exit 1
  96. fi
  97. # Setting `VIDEO_PORT` to none disables RANDR/XRANDR, do not set this if using datacenter GPUs
  98. if [ "$(echo ${VIDEO_PORT} | tr '[:upper:]' '[:lower:]')" = "none" ]; then
  99. export CONNECTED_MONITOR="--use-display-device=None"
  100. # 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
  101. else
  102. export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT}"
  103. fi
  104. # 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
  105. HEX_ID="$(nvidia-smi --query-gpu=pci.bus_id --id="$GPU_SELECT" --format=csv,noheader | head -n1)"
  106. IFS=":." ARR_ID=($HEX_ID)
  107. unset IFS
  108. BUS_ID="PCI:$((16#${ARR_ID[1]}))@$((16#${ARR_ID[0]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))"
  109. # A custom modeline should be generated because there is no monitor to fetch this information normally
  110. export MODELINE="$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n 2p)"
  111. # Generate /etc/X11/xorg.conf with nvidia-xconfig
  112. 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}
  113. # Guarantee that the X server starts without a monitor by adding more options to the configuration
  114. 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
  115. sed -i '/Driver\s\+"nvidia"/a\ Option "PrimaryGPU" "True"' /etc/X11/xorg.conf
  116. # Support external GPUs
  117. sed -i '/Driver\s\+"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
  118. # Add custom generated modeline to the configuration
  119. sed -i '/Section\s\+"Monitor"/a\ '"$MODELINE" /etc/X11/xorg.conf
  120. # Prevent interference between GPUs, add this to the host or other containers running Xorg as well
  121. 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
  122. # 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`
  123. ln -snf /dev/ptmx /dev/tty7 || sudo-root ln -snf /dev/ptmx /dev/tty7 || echo 'Failed to create /dev/tty7 device'
  124. # Run Xorg server with required extensions
  125. /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" &
  126. # Wait for X server to start
  127. echo 'Waiting for X Socket' && until [ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]; do sleep 0.5; done && echo 'X Server is ready'
  128. # Start KDE desktop environment
  129. export XDG_SESSION_ID="${DISPLAY#*:}"
  130. export QT_LOGGING_RULES='*.debug=false;qt.qpa.*=false'
  131. /usr/bin/startplasma-x11 &
  132. # Start Fcitx input method framework
  133. /usr/bin/fcitx &
  134. # Add custom processes right below this line, or within `supervisord.conf` to perform service management similar to systemd
  135. echo "Session Running. Press [Return] to exit."
  136. read