entrypoint.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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 -pm1777 /dev/input || sudo-root mkdir -pm1777 /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. chmod 777 /dev/input/js* || sudo-root chmod 777 /dev/input/js* || echo 'Failed to change permission for joystick interposer devices'
  28. # Set default display
  29. export DISPLAY="${DISPLAY:-:20}"
  30. # PipeWire-Pulse server socket path
  31. export PIPEWIRE_LATENCY="128/48000"
  32. export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}"
  33. export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-/tmp}}"
  34. export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}"
  35. export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR:-/tmp}/pulse}/native}"
  36. if ! command -v nvidia-xconfig >/dev/null 2>&1; then
  37. # Install NVIDIA userspace driver components including X graphic libraries, keep contents same between docker-nvidia-glx-desktop and docker-nvidia-egl-desktop
  38. 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/')"
  39. if [ -z "${NVIDIA_DRIVER_VERSION}" ]; then
  40. # Driver version is provided by the kernel through the container toolkit, prioritize kernel driver version if available
  41. if [ -f "/proc/driver/nvidia/version" ]; then
  42. 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}}')"
  43. elif command -v nvidia-smi >/dev/null 2>&1; then
  44. # Use NVIDIA-SMI when not available
  45. export NVIDIA_DRIVER_VERSION="$(nvidia-smi --version | grep 'DRIVER version' | cut -d: -f2 | tr -d ' ')"
  46. else
  47. echo 'Failed to find NVIDIA GPU driver version, container will likely not start because of no NVIDIA container toolkit or NVIDIA GPU driver present'
  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'
  55. fi
  56. if [ -f "/tmp/NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" ]; then
  57. # Extract installer before installing
  58. rm -rf "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}"
  59. sh "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}.run" -x
  60. cd "NVIDIA-Linux-${NVIDIA_DRIVER_ARCH}-${NVIDIA_DRIVER_VERSION}"
  61. # Run NVIDIA driver installation without the kernel modules and host components
  62. sudo ./nvidia-installer --silent \
  63. --no-kernel-module \
  64. --install-compat32-libs \
  65. --no-nouveau-check \
  66. --no-nvidia-modprobe \
  67. --no-systemd \
  68. --no-rpms \
  69. --no-backup \
  70. --no-check-for-alternate-installs
  71. rm -rf /tmp/NVIDIA* && cd ~
  72. else
  73. echo 'Unless using non-NVIDIA GPUs, container will likely not work correctly'
  74. fi
  75. fi
  76. # Remove existing Xorg configuration
  77. if [ -f "/etc/X11/xorg.conf" ]; then
  78. rm -f "/etc/X11/xorg.conf"
  79. fi
  80. # Get first GPU device of specified visible devices when `NVIDIA_VISIBLE_DEVICES` devices are specified
  81. if [ "${NVIDIA_VISIBLE_DEVICES}" != "all" ] && [ "${NVIDIA_VISIBLE_DEVICES}" != "none" ] && [ "${NVIDIA_VISIBLE_DEVICES}" != "void" ] && [ -n "${NVIDIA_VISIBLE_DEVICES}" ]; then
  82. export GPU_SELECT="$(nvidia-smi --id=$(echo ${NVIDIA_VISIBLE_DEVICES} | cut -d ',' -f1) --query-gpu=uuid --format=csv,noheader | head -n1)"
  83. # Get first GPU device out of all visible devices in other situations
  84. else
  85. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  86. fi
  87. if [ -z "${GPU_SELECT}" ]; then
  88. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  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. fi
  94. # Setting `VIDEO_PORT` to none disables RANDR/XRANDR, causing potential compatibility issues, set to DFP if using datacenter GPUs
  95. if [ "$(echo ${VIDEO_PORT} | tr '[:upper:]' '[:lower:]')" = "none" ]; then
  96. export CONNECTED_MONITOR="--use-display-device=None"
  97. # 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
  98. else
  99. export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT:-DFP}"
  100. fi
  101. # 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
  102. HEX_ID="$(nvidia-smi --query-gpu=pci.bus_id --id=${GPU_SELECT} --format=csv,noheader | head -n1)"
  103. IFS=":." ARR_ID=(${HEX_ID})
  104. unset IFS
  105. BUS_ID="PCI:$(printf '%u' 0x${ARR_ID[1]})@$(printf '%u' 0x${ARR_ID[0]}):$(printf '%u' 0x${ARR_ID[2]}):$(printf '%u' 0x${ARR_ID[3]})"
  106. # A custom modeline should be generated because there is no monitor to fetch this information normally
  107. export MODELINE="$(cvt -r ${DISPLAY_SIZEW} ${DISPLAY_SIZEH} ${DISPLAY_REFRESH} | sed -n 2p)"
  108. # Generate /etc/X11/xorg.conf with nvidia-xconfig
  109. 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}
  110. # Guarantee that the X server starts without a monitor by adding more options to the configuration
  111. 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
  112. # Support external GPUs
  113. sed -i '/Driver\s\+"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
  114. # Add custom generated modeline to the configuration
  115. sed -i '/Section\s\+"Monitor"/a\ '"${MODELINE}" /etc/X11/xorg.conf
  116. # Disable screen blanking in X11
  117. sed -i '/"DPMS"/d' /etc/X11/xorg.conf
  118. sed -i '/Section\s\+"Monitor"/a\ Option "DPMS" "False"' /etc/X11/xorg.conf
  119. # Prevent interference between GPUs, add this to the host or other containers running Xorg as well
  120. 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
  121. # Real sudo (sudo-root) is required in Ubuntu 20.04 but not in newer Ubuntu, this symbolic link enables running Xorg inside a container with `-sharevts`
  122. ln -snf /dev/ptmx /dev/tty7 || sudo-root ln -snf /dev/ptmx /dev/tty7 || echo 'Failed to create /dev/tty7 device'
  123. # Run Xorg server with required extensions
  124. /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" &
  125. # Wait for X server to start
  126. echo 'Waiting for X Socket' && until [ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]; do sleep 0.5; done && echo 'X Server is ready'
  127. # Start KDE desktop environment
  128. export XDG_SESSION_ID="${DISPLAY#*:}"
  129. export QT_LOGGING_RULES="${QT_LOGGING_RULES:-*.debug=false;qt.qpa.*=false}"
  130. /usr/bin/dbus-launch --exit-with-session /usr/bin/startplasma-x11 &
  131. # Start Fcitx input method framework
  132. /usr/bin/fcitx &
  133. # Add custom processes right below this line, or within `supervisord.conf` to perform service management similar to systemd
  134. echo "Session Running. Press [Return] to exit."
  135. read