entrypoint.sh 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #!/bin/bash
  2. # Adapted from docker-selkies-glx-desktop for an XFCE-only NVIDIA image.
  3. # This Source Code Form is subject to the Mozilla Public License, v. 2.0.
  4. set -Eeuo pipefail
  5. trap 'echo "Desktop entrypoint received a termination signal"' HUP INT QUIT TERM
  6. export DISPLAY="${DISPLAY:-:20}"
  7. export DISPLAY_SIZEW="${DISPLAY_SIZEW:-1920}"
  8. export DISPLAY_SIZEH="${DISPLAY_SIZEH:-1080}"
  9. export DISPLAY_REFRESH="${DISPLAY_REFRESH:-60}"
  10. export DISPLAY_DPI="${DISPLAY_DPI:-96}"
  11. export DISPLAY_CDEPTH="${DISPLAY_CDEPTH:-24}"
  12. export VIDEO_PORT="${VIDEO_PORT:-DFP}"
  13. export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp/runtime-${USER:-ubuntu}}"
  14. export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-${XDG_RUNTIME_DIR}}"
  15. export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-${XDG_RUNTIME_DIR}/pulse}"
  16. export PULSE_SERVER="${PULSE_SERVER:-unix:${PULSE_RUNTIME_PATH}/native}"
  17. until [[ -d "${XDG_RUNTIME_DIR}" ]]; do
  18. sleep 0.5
  19. done
  20. sudo-root chown "$(id -u):$(id -g)" "${HOME}" || true
  21. if [[ -n "${PASSWD:-}" ]]; then
  22. printf '%s:%s\n' "${USER}" "${PASSWD}" | sudo-root chpasswd || true
  23. fi
  24. rm -rf /tmp/.X11-unix "/tmp/.X${DISPLAY#:}-lock" "${HOME}/.cache" || true
  25. sudo-root ln -snf "/usr/share/zoneinfo/${TZ:-UTC}" /etc/localtime || true
  26. printf '%s\n' "${TZ:-UTC}" | sudo-root tee /etc/timezone >/dev/null || true
  27. # Joystick interposer support.
  28. SELKIES_INTERPOSER_PATH="$(
  29. find /usr/lib /usr/lib64 /usr/local/lib \
  30. -name 'selkies_joystick_interposer.so' \
  31. -print -quit 2>/dev/null || true
  32. )"
  33. if [[ -n "${SELKIES_INTERPOSER_PATH}" ]]; then
  34. export LD_PRELOAD="${SELKIES_INTERPOSER_PATH}${LD_PRELOAD:+:${LD_PRELOAD}}"
  35. export SDL_JOYSTICK_DEVICE="${SDL_JOYSTICK_DEVICE:-/dev/input/js0}"
  36. sudo-root install -d -m 1777 /dev/input || true
  37. for joystick in /dev/input/js{0..3}; do
  38. sudo-root touch "${joystick}" || true
  39. sudo-root chmod 0777 "${joystick}" || true
  40. done
  41. fi
  42. install_nvidia_userspace() {
  43. command -v nvidia-smi >/dev/null 2>&1 || {
  44. echo "NVIDIA Container Toolkit has not exposed nvidia-smi." >&2
  45. return 1
  46. }
  47. if command -v nvidia-xconfig >/dev/null 2>&1; then
  48. return 0
  49. fi
  50. local driver_arch driver_version installer archive_dir
  51. driver_arch="$(
  52. dpkg --print-architecture |
  53. sed -e 's/arm64/aarch64/' \
  54. -e 's/armhf/32bit-ARM/' \
  55. -e 's/i.*86/x86/' \
  56. -e 's/amd64/x86_64/' \
  57. -e 's/unknown/x86_64/'
  58. )"
  59. driver_version="${NVIDIA_DRIVER_VERSION:-}"
  60. if [[ -z "${driver_version}" && -f /proc/driver/nvidia/version ]]; then
  61. driver_version="$(
  62. head -n 1 /proc/driver/nvidia/version |
  63. awk '{for (i=1; i<=NF; i++) if ($i ~ /^[0-9]+\.[0-9.]+$/) {print $i; exit}}'
  64. )"
  65. fi
  66. if [[ -z "${driver_version}" ]]; then
  67. driver_version="$(
  68. nvidia-smi --query-gpu=driver_version --format=csv,noheader |
  69. head -n 1
  70. )"
  71. fi
  72. if [[ -z "${driver_version}" ]]; then
  73. echo "Unable to determine the host NVIDIA driver version." >&2
  74. return 1
  75. fi
  76. installer="/tmp/NVIDIA-Linux-${driver_arch}-${driver_version}.run"
  77. archive_dir="/tmp/NVIDIA-Linux-${driver_arch}-${driver_version}"
  78. echo "Installing NVIDIA ${driver_version} userspace GLX components"
  79. curl -fsSL \
  80. "https://international.download.nvidia.com/XFree86/Linux-${driver_arch}/${driver_version}/NVIDIA-Linux-${driver_arch}-${driver_version}.run" \
  81. -o "${installer}" \
  82. || curl -fsSL \
  83. "https://international.download.nvidia.com/tesla/${driver_version}/NVIDIA-Linux-${driver_arch}-${driver_version}.run" \
  84. -o "${installer}"
  85. rm -rf "${archive_dir}"
  86. (
  87. cd /tmp
  88. sh "${installer}" -x
  89. )
  90. sudo-root "${archive_dir}/nvidia-installer" \
  91. --silent \
  92. --no-kernel-module \
  93. --no-install-compat32-libs \
  94. --no-nouveau-check \
  95. --no-nvidia-modprobe \
  96. --no-systemd \
  97. --no-rpms \
  98. --no-backup \
  99. --no-check-for-alternate-installs
  100. rm -rf "${installer}" "${archive_dir}"
  101. }
  102. install_nvidia_userspace
  103. # Always select the first GPU visible inside the container. Device indexes are
  104. # renumbered by NVIDIA Container Toolkit, so the host-side index is unreliable.
  105. GPU_SELECT="$(
  106. nvidia-smi --query-gpu=uuid --format=csv,noheader |
  107. head -n 1
  108. )"
  109. if [[ -z "${GPU_SELECT}" ]]; then
  110. echo "No visible NVIDIA GPU was detected." >&2
  111. exit 1
  112. fi
  113. HEX_ID="$(
  114. nvidia-smi \
  115. --id="${GPU_SELECT}" \
  116. --query-gpu=pci.bus_id \
  117. --format=csv,noheader |
  118. head -n 1
  119. )"
  120. IFS=':.' read -r domain bus device function <<<"${HEX_ID}"
  121. BUS_ID="PCI:$((16#${bus}))@$((16#${domain})):$((16#${device})):$((16#${function}))"
  122. MODELINE="$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n '2p')"
  123. MODE_NAME="$(awk '{print $2}' <<<"${MODELINE}" | tr -d '"')"
  124. if [[ "${VIDEO_PORT,,}" == "none" ]]; then
  125. CONNECTED_MONITOR=(--use-display-device=None)
  126. else
  127. CONNECTED_MONITOR=(--connected-monitor="${VIDEO_PORT}")
  128. fi
  129. sudo-root rm -f /etc/X11/xorg.conf
  130. sudo-root nvidia-xconfig \
  131. --virtual="${DISPLAY_SIZEW}x${DISPLAY_SIZEH}" \
  132. --depth="${DISPLAY_CDEPTH}" \
  133. --mode="${MODE_NAME}" \
  134. --allow-empty-initial-configuration \
  135. --no-probe-all-gpus \
  136. --busid="${BUS_ID}" \
  137. --include-implicit-metamodes \
  138. --mode-debug \
  139. --no-sli \
  140. --no-base-mosaic \
  141. --only-one-x-screen \
  142. "${CONNECTED_MONITOR[@]}"
  143. sudo-root sed -i \
  144. '/Driver[[:space:]]*"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck,NoEdidMaxPClkCheck,NoMaxSizeCheck,NoHorizSyncCheck,NoVertRefreshCheck,NoVirtualSizeCheck,NoExtendedGpuCapabilitiesCheck,NoTotalSizeCheck,NoDualLinkDVICheck,NoDisplayPortBandwidthCheck,AllowNon3DVisionModes,AllowNonHDMI3DModes,AllowNonEdidModes,NoEdidHDMI2Check,AllowDpInterlaced"' \
  145. /etc/X11/xorg.conf
  146. sudo-root sed -i \
  147. '/Driver[[:space:]]*"nvidia"/a\ Option "AllowExternalGpus" "True"' \
  148. /etc/X11/xorg.conf
  149. sudo-root sed -i \
  150. '/Section[[:space:]]*"Monitor"/a\ '"${MODELINE}" \
  151. /etc/X11/xorg.conf
  152. sudo-root sed -i '/"DPMS"/d' /etc/X11/xorg.conf
  153. sudo-root sed -i \
  154. '/Section[[:space:]]*"Monitor"/a\ Option "DPMS" "False"' \
  155. /etc/X11/xorg.conf
  156. cat <<'EOF' | sudo-root tee -a /etc/X11/xorg.conf >/dev/null
  157. Section "ServerFlags"
  158. Option "DontVTSwitch" "True"
  159. Option "DontZap" "True"
  160. Option "AllowMouseOpenFail" "True"
  161. Option "AutoAddGPU" "False"
  162. EndSection
  163. EOF
  164. sudo-root ln -snf /dev/ptmx /dev/tty7
  165. /usr/lib/xorg/Xorg \
  166. "${DISPLAY}" \
  167. vt7 \
  168. -noreset \
  169. -novtswitch \
  170. -sharevts \
  171. -nolisten tcp \
  172. -ac \
  173. -dpi "${DISPLAY_DPI}" \
  174. +extension COMPOSITE \
  175. +extension DAMAGE \
  176. +extension GLX \
  177. +extension RANDR \
  178. +extension RENDER \
  179. +extension MIT-SHM \
  180. +extension XFIXES \
  181. +extension XTEST \
  182. &
  183. XORG_PID=$!
  184. echo "Waiting for X socket ${DISPLAY}"
  185. until [[ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]]; do
  186. if ! kill -0 "${XORG_PID}" 2>/dev/null; then
  187. echo "Xorg exited before creating its socket." >&2
  188. exit 1
  189. fi
  190. sleep 0.5
  191. done
  192. xset -dpms || true
  193. xset s off || true
  194. xset s noblank || true
  195. export XDG_SESSION_ID="${DISPLAY#*:}"
  196. xfce4-session &
  197. XFCE_PID=$!
  198. wait "${XFCE_PID}"