entrypoint.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. # Allow starting Xorg from a pseudoterminal instead of strictly on a tty console
  76. if [ ! -f /etc/X11/Xwrapper.config ]; then
  77. echo -e "allowed_users=anybody\nneeds_root_rights=yes" | tee /etc/X11/Xwrapper.config > /dev/null
  78. fi
  79. if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
  80. sed -i "s/allowed_users=console/allowed_users=anybody/;$ a needs_root_rights=yes" /etc/X11/Xwrapper.config
  81. fi
  82. # Remove existing Xorg configuration
  83. if [ -f "/etc/X11/xorg.conf" ]; then
  84. rm -f "/etc/X11/xorg.conf"
  85. fi
  86. # Get first GPU device if all devices are available or `NVIDIA_VISIBLE_DEVICES` is not set
  87. if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ] || [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
  88. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  89. # Get first GPU device out of the visible devices in other situations
  90. else
  91. export GPU_SELECT="$(nvidia-smi --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid --format=csv,noheader | head -n1)"
  92. if [ -z "$GPU_SELECT" ]; then
  93. export GPU_SELECT="$(nvidia-smi --query-gpu=uuid --format=csv,noheader | head -n1)"
  94. fi
  95. fi
  96. if [ -z "$GPU_SELECT" ]; then
  97. echo "No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Exiting."
  98. exit 1
  99. fi
  100. # Setting `VIDEO_PORT` to none disables RANDR/XRANDR, do not set this if using datacenter GPUs
  101. if [ "$(echo ${VIDEO_PORT} | tr '[:upper:]' '[:lower:]')" = "none" ]; then
  102. export CONNECTED_MONITOR="--use-display-device=None"
  103. # 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
  104. else
  105. export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT}"
  106. fi
  107. # 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
  108. HEX_ID="$(nvidia-smi --query-gpu=pci.bus_id --id="$GPU_SELECT" --format=csv,noheader | head -n1)"
  109. IFS=":." ARR_ID=($HEX_ID)
  110. unset IFS
  111. BUS_ID="PCI:$((16#${ARR_ID[1]}))@$((16#${ARR_ID[0]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))"
  112. # A custom modeline should be generated because there is no monitor to fetch this information normally
  113. export MODELINE="$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n 2p)"
  114. # Generate /etc/X11/xorg.conf with nvidia-xconfig
  115. 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}
  116. # Guarantee that the X server starts without a monitor by adding more options to the configuration
  117. 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
  118. # Support external GPUs
  119. sed -i '/Driver\s\+"nvidia"/a\ Option "AllowExternalGpus" "True"' /etc/X11/xorg.conf
  120. # Add custom generated modeline to the configuration
  121. sed -i '/Section\s\+"Monitor"/a\ '"$MODELINE" /etc/X11/xorg.conf
  122. # Disable screen blanking in X11
  123. sed -i '/"DPMS"/d' /etc/X11/xorg.conf
  124. sed -i '/Section\s\+"Monitor"/a\ Option "DPMS" "False"' /etc/X11/xorg.conf
  125. # Prevent interference between GPUs, add this to the host or other containers running Xorg as well
  126. echo -e "Section \"ServerFlags\"\n Option \"DontVTSwitch\" \"True\"\n Option \"DontZap\" \"True\"\n Option \"AllowMouseOpenFail\" \"True\"\n Option \"AutoAddGPU\" \"False\"\n Option \"AutoBindGPU\" \"False\"\nEndSection" | tee -a /etc/X11/xorg.conf > /dev/null
  127. # 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`
  128. ln -snf /dev/ptmx /dev/tty7 || sudo-root ln -snf /dev/ptmx /dev/tty7 || echo 'Failed to create /dev/tty7 device'
  129. # Run Xorg server with required extensions
  130. /usr/bin/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" &
  131. # Wait for X server to start
  132. echo 'Waiting for X Socket' && until [ -S "/tmp/.X11-unix/X${DISPLAY#*:}" ]; do sleep 0.5; done && echo 'X Server is ready'
  133. # Start KDE desktop environment
  134. export XDG_SESSION_ID="${DISPLAY#*:}"
  135. export QT_LOGGING_RULES="${QT_LOGGING_RULES:-*.debug=false;qt.qpa.*=false}"
  136. /usr/bin/dbus-launch --exit-with-session /usr/bin/startplasma-x11 &
  137. # Start Fcitx input method framework
  138. /usr/bin/fcitx &
  139. # Add custom processes right below this line, or within `supervisord.conf` to perform service management similar to systemd
  140. echo "Session Running. Press [Return] to exit."
  141. read