entrypoint.sh 9.8 KB

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