check-requirements.sh 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env sh
  2. #
  3. # Copyright (c) Microsoft Corporation. All rights reserved.
  4. #
  5. set -e
  6. # The script checks necessary server requirements for the classic server
  7. # scenarios. Currently, the script can exit with any of the following
  8. # 2 exit codes and should be handled accordingly on the extension side.
  9. #
  10. # 0: All requirements are met, use the default server.
  11. # 99: Unsupported OS, abort server startup with appropriate error message.
  12. #
  13. # Do not remove this check.
  14. # Provides a way to skip the server requirements check from
  15. # outside the install flow. A system process can create this
  16. # file before the server is downloaded and installed.
  17. if [ -f "/tmp/vscode-skip-server-requirements-check" ] || [ -n "$VSCODE_SERVER_CUSTOM_GLIBC_LINKER" ]; then
  18. echo "!!! WARNING: Skipping server pre-requisite check !!!"
  19. echo "!!! Server stability is not guaranteed. Proceed at your own risk. !!!"
  20. exit 0
  21. fi
  22. ARCH=$(uname -m)
  23. found_required_glibc=0
  24. found_required_glibcxx=0
  25. MIN_GLIBCXX_VERSION="3.4.25"
  26. # Extract the ID value from /etc/os-release
  27. if [ -f /etc/os-release ]; then
  28. OS_ID="$(cat /etc/os-release | grep -Eo 'ID=([^"]+)' | sed -n '1s/ID=//p')"
  29. if [ "$OS_ID" = "nixos" ]; then
  30. echo "Warning: NixOS detected, skipping GLIBC check"
  31. exit 0
  32. fi
  33. fi
  34. # Based on https://github.com/bminor/glibc/blob/520b1df08de68a3de328b65a25b86300a7ddf512/elf/cache.c#L162-L245
  35. case $ARCH in
  36. x86_64) LDCONFIG_ARCH="x86-64";;
  37. armv7l | armv8l)
  38. MIN_GLIBCXX_VERSION="3.4.26"
  39. LDCONFIG_ARCH="hard-float"
  40. ;;
  41. arm64 | aarch64)
  42. BITNESS=$(getconf LONG_BIT)
  43. if [ "$BITNESS" = "32" ]; then
  44. # Can have 32-bit userland on 64-bit kernel
  45. LDCONFIG_ARCH="hard-float"
  46. else
  47. LDCONFIG_ARCH="AArch64"
  48. fi
  49. ;;
  50. esac
  51. if [ "$OS_ID" != "alpine" ]; then
  52. if [ -f /sbin/ldconfig ]; then
  53. # Look up path
  54. libstdcpp_paths=$(/sbin/ldconfig -p | grep 'libstdc++.so.6')
  55. if [ "$(echo "$libstdcpp_paths" | wc -l)" -gt 1 ]; then
  56. libstdcpp_path=$(echo "$libstdcpp_paths" | grep "$LDCONFIG_ARCH" | awk '{print $NF}')
  57. else
  58. libstdcpp_path=$(echo "$libstdcpp_paths" | awk '{print $NF}')
  59. fi
  60. elif [ -f /usr/lib/libstdc++.so.6 ]; then
  61. # Typical path
  62. libstdcpp_path='/usr/lib/libstdc++.so.6'
  63. elif [ -f /usr/lib64/libstdc++.so.6 ]; then
  64. # Typical path
  65. libstdcpp_path='/usr/lib64/libstdc++.so.6'
  66. else
  67. echo "Warning: Can't find libstdc++.so or ldconfig, can't verify libstdc++ version"
  68. fi
  69. while [ -n "$libstdcpp_path" ]; do
  70. # Extracts the version number from the path, e.g. libstdc++.so.6.0.22 -> 6.0.22
  71. # which is then compared based on the fact that release versioning and symbol versioning
  72. # are aligned for libstdc++. Refs https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
  73. # (i-e) GLIBCXX_3.4.<release> is provided by libstdc++.so.6.y.<release>
  74. libstdcpp_path_line=$(echo "$libstdcpp_path" | head -n1)
  75. libstdcpp_real_path=$(readlink -f "$libstdcpp_path_line")
  76. libstdcpp_version=$(grep -ao 'GLIBCXX_[0-9]*\.[0-9]*\.[0-9]*' "$libstdcpp_real_path" | sort -V | tail -1)
  77. libstdcpp_version_number=$(echo "$libstdcpp_version" | sed 's/GLIBCXX_//')
  78. if [ "$(printf '%s\n' "$MIN_GLIBCXX_VERSION" "$libstdcpp_version_number" | sort -V | head -n1)" = "$MIN_GLIBCXX_VERSION" ]; then
  79. found_required_glibcxx=1
  80. break
  81. fi
  82. libstdcpp_path=$(echo "$libstdcpp_path" | tail -n +2) # remove first line
  83. done
  84. else
  85. echo "Warning: alpine distro detected, skipping GLIBCXX check"
  86. found_required_glibcxx=1
  87. fi
  88. if [ "$found_required_glibcxx" = "0" ]; then
  89. echo "Warning: Missing GLIBCXX >= $MIN_GLIBCXX_VERSION! from $libstdcpp_real_path"
  90. fi
  91. if [ "$OS_ID" = "alpine" ]; then
  92. MUSL_RTLDLIST="/lib/ld-musl-aarch64.so.1 /lib/ld-musl-x86_64.so.1"
  93. for rtld in ${MUSL_RTLDLIST}; do
  94. if [ -x $rtld ]; then
  95. musl_version=$("$rtld" --version 2>&1 | grep "Version" | awk '{print $NF}')
  96. break
  97. fi
  98. done
  99. if [ "$(printf '%s\n' "1.2.3" "$musl_version" | sort -V | head -n1)" != "1.2.3" ]; then
  100. echo "Error: Unsupported alpine distribution. Please refer to our supported distro section https://aka.ms/vscode-remote/linux for additional information."
  101. exit 99
  102. fi
  103. found_required_glibc=1
  104. elif [ -z "$(ldd --version 2>&1 | grep 'musl libc')" ]; then
  105. if [ -f /sbin/ldconfig ]; then
  106. # Look up path
  107. libc_paths=$(/sbin/ldconfig -p | grep 'libc.so.6')
  108. if [ "$(echo "$libc_paths" | wc -l)" -gt 1 ]; then
  109. libc_path=$(echo "$libc_paths" | grep "$LDCONFIG_ARCH" | awk '{print $NF}')
  110. else
  111. libc_path=$(echo "$libc_paths" | awk '{print $NF}')
  112. fi
  113. elif [ -f /usr/lib/libc.so.6 ]; then
  114. # Typical path
  115. libc_path='/usr/lib/libc.so.6'
  116. elif [ -f /lib64/libc.so.6 ]; then
  117. # Typical path (OpenSUSE)
  118. libc_path='/lib64/libc.so.6'
  119. elif [ -f /usr/lib64/libc.so.6 ]; then
  120. # Typical path
  121. libc_path='/usr/lib64/libc.so.6'
  122. else
  123. echo "Warning: Can't find libc.so or ldconfig, can't verify libc version"
  124. fi
  125. while [ -n "$libc_path" ]; do
  126. # Rather than trusting the output of ldd --version (which is not always accurate)
  127. # we instead use the version of the cached libc.so.6 file itself.
  128. libc_path_line=$(echo "$libc_path" | head -n1)
  129. libc_real_path=$(readlink -f "$libc_path_line")
  130. libc_version=$(cat "$libc_real_path" | sed -n 's/.*release version \([0-9]\+\.[0-9]\+\).*/\1/p')
  131. if [ "$(printf '%s\n' "2.28" "$libc_version" | sort -V | head -n1)" = "2.28" ]; then
  132. found_required_glibc=1
  133. break
  134. fi
  135. libc_path=$(echo "$libc_path" | tail -n +2) # remove first line
  136. done
  137. if [ "$found_required_glibc" = "0" ]; then
  138. echo "Warning: Missing GLIBC >= 2.28! from $libc_real_path"
  139. fi
  140. else
  141. echo "Warning: musl detected, skipping GLIBC check"
  142. found_required_glibc=1
  143. fi
  144. if [ "$found_required_glibc" = "0" ] || [ "$found_required_glibcxx" = "0" ]; then
  145. echo "Error: Missing required dependencies. Please refer to our FAQ https://aka.ms/vscode-remote/faq/old-linux for additional information."
  146. # Custom exit code based on https://tldp.org/LDP/abs/html/exitcodes.html
  147. exit 99
  148. fi