rustup-init.sh 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. #!/bin/sh
  2. # Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  3. # SPDX-License-Identifier: Apache-2.0
  4. # SPDX-License-Identifier: MIT
  5. # shellcheck shell=dash
  6. # This is just a little script that can be downloaded from the internet to
  7. # install rustup. It just does platform detection, downloads the installer
  8. # and runs it.
  9. # It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
  10. # extension. Note: Most shells limit `local` to 1 var per line, contra bash.
  11. set -u
  12. # If RUSTUP_UPDATE_ROOT is unset or empty, default it.
  13. RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}"
  14. #XXX: If you change anything here, please make the same changes in setup_mode.rs
  15. usage() {
  16. cat 1>&2 <<EOF
  17. rustup-init 1.22.1 (76644d669 2020-07-08)
  18. The installer for rustup
  19. USAGE:
  20. rustup-init [FLAGS] [OPTIONS]
  21. FLAGS:
  22. -v, --verbose Enable verbose output
  23. -q, --quiet Disable progress output
  24. -y Disable confirmation prompt.
  25. --no-modify-path Don't configure the PATH environment variable
  26. -h, --help Prints help information
  27. -V, --version Prints version information
  28. OPTIONS:
  29. --default-host <default-host> Choose a default host triple
  30. --default-toolchain <default-toolchain> Choose a default toolchain to install
  31. --default-toolchain none Do not install any toolchains
  32. --profile [minimal|default|complete] Choose a profile
  33. -c, --component <components>... Component name to also install
  34. -t, --target <targets>... Target name to also install
  35. EOF
  36. }
  37. main() {
  38. downloader --check
  39. need_cmd uname
  40. need_cmd mktemp
  41. need_cmd chmod
  42. need_cmd mkdir
  43. need_cmd rm
  44. need_cmd rmdir
  45. get_architecture || return 1
  46. local _arch="$RETVAL"
  47. assert_nz "$_arch" "arch"
  48. local _ext=""
  49. case "$_arch" in
  50. *windows*)
  51. _ext=".exe"
  52. ;;
  53. esac
  54. local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}"
  55. local _dir
  56. _dir="$(mktemp -d 2>/dev/null || ensure mktemp -d -t rustup)"
  57. local _file="${_dir}/rustup-init${_ext}"
  58. local _ansi_escapes_are_valid=false
  59. if [ -t 2 ]; then
  60. if [ "${TERM+set}" = 'set' ]; then
  61. case "$TERM" in
  62. xterm*|rxvt*|urxvt*|linux*|vt*)
  63. _ansi_escapes_are_valid=true
  64. ;;
  65. esac
  66. fi
  67. fi
  68. # check if we have to use /dev/tty to prompt the user
  69. local need_tty=yes
  70. for arg in "$@"; do
  71. case "$arg" in
  72. -h|--help)
  73. usage
  74. exit 0
  75. ;;
  76. -y)
  77. # user wants to skip the prompt -- we don't need /dev/tty
  78. need_tty=no
  79. ;;
  80. *)
  81. ;;
  82. esac
  83. done
  84. if $_ansi_escapes_are_valid; then
  85. printf "\33[1minfo:\33[0m downloading installer\n" 1>&2
  86. else
  87. printf '%s\n' 'info: downloading installer' 1>&2
  88. fi
  89. ensure mkdir -p "$_dir"
  90. ensure downloader "$_url" "$_file" "$_arch"
  91. ensure chmod u+x "$_file"
  92. if [ ! -x "$_file" ]; then
  93. printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
  94. printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init${_ext}." 1>&2
  95. exit 1
  96. fi
  97. if [ "$need_tty" = "yes" ]; then
  98. # The installer is going to want to ask for confirmation by
  99. # reading stdin. This script was piped into `sh` though and
  100. # doesn't have stdin to pass to its children. Instead we're going
  101. # to explicitly connect /dev/tty to the installer's stdin.
  102. if [ ! -t 1 ]; then
  103. err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
  104. fi
  105. ignore "$_file" "$@" < /dev/tty
  106. else
  107. ignore "$_file" "$@"
  108. fi
  109. local _retval=$?
  110. ignore rm "$_file"
  111. ignore rmdir "$_dir"
  112. return "$_retval"
  113. }
  114. get_bitness() {
  115. need_cmd head
  116. # Architecture detection without dependencies beyond coreutils.
  117. # ELF files start out "\x7fELF", and the following byte is
  118. # 0x01 for 32-bit and
  119. # 0x02 for 64-bit.
  120. # The printf builtin on some shells like dash only supports octal
  121. # escape sequences, so we use those.
  122. local _current_exe_head
  123. _current_exe_head=$(head -c 5 /proc/self/exe )
  124. if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then
  125. echo 32
  126. elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then
  127. echo 64
  128. else
  129. err "unknown platform bitness"
  130. fi
  131. }
  132. get_endianness() {
  133. local cputype=$1
  134. local suffix_eb=$2
  135. local suffix_el=$3
  136. # detect endianness without od/hexdump, like get_bitness() does.
  137. need_cmd head
  138. need_cmd tail
  139. local _current_exe_endianness
  140. _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)"
  141. if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then
  142. echo "${cputype}${suffix_el}"
  143. elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then
  144. echo "${cputype}${suffix_eb}"
  145. else
  146. err "unknown platform endianness"
  147. fi
  148. }
  149. get_architecture() {
  150. local _ostype _cputype _bitness _arch _clibtype
  151. _ostype="$(uname -s)"
  152. _cputype="$(uname -m)"
  153. _clibtype="gnu"
  154. if [ "$_ostype" = Linux ]; then
  155. if [ "$(uname -o)" = Android ]; then
  156. _ostype=Android
  157. fi
  158. if ldd --version 2>&1 | grep -q 'musl'; then
  159. _clibtype="musl"
  160. fi
  161. fi
  162. if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
  163. # Darwin `uname -m` lies
  164. if sysctl hw.optional.x86_64 | grep -q ': 1'; then
  165. _cputype=x86_64
  166. fi
  167. fi
  168. case "$_ostype" in
  169. Android)
  170. _ostype=linux-android
  171. ;;
  172. Linux)
  173. _ostype=unknown-linux-$_clibtype
  174. _bitness=$(get_bitness)
  175. ;;
  176. FreeBSD)
  177. _ostype=unknown-freebsd
  178. ;;
  179. NetBSD)
  180. _ostype=unknown-netbsd
  181. ;;
  182. DragonFly)
  183. _ostype=unknown-dragonfly
  184. ;;
  185. Darwin)
  186. _ostype=apple-darwin
  187. ;;
  188. MINGW* | MSYS* | CYGWIN*)
  189. _ostype=pc-windows-gnu
  190. ;;
  191. *)
  192. err "unrecognized OS type: $_ostype"
  193. ;;
  194. esac
  195. case "$_cputype" in
  196. i386 | i486 | i686 | i786 | x86)
  197. _cputype=i686
  198. ;;
  199. xscale | arm)
  200. _cputype=arm
  201. if [ "$_ostype" = "linux-android" ]; then
  202. _ostype=linux-androideabi
  203. fi
  204. ;;
  205. armv6l)
  206. _cputype=arm
  207. if [ "$_ostype" = "linux-android" ]; then
  208. _ostype=linux-androideabi
  209. else
  210. _ostype="${_ostype}eabihf"
  211. fi
  212. ;;
  213. armv7l | armv8l)
  214. _cputype=armv7
  215. if [ "$_ostype" = "linux-android" ]; then
  216. _ostype=linux-androideabi
  217. else
  218. _ostype="${_ostype}eabihf"
  219. fi
  220. ;;
  221. aarch64)
  222. _cputype=aarch64
  223. ;;
  224. x86_64 | x86-64 | x64 | amd64)
  225. _cputype=x86_64
  226. ;;
  227. mips)
  228. _cputype=$(get_endianness mips '' el)
  229. ;;
  230. mips64)
  231. if [ "$_bitness" -eq 64 ]; then
  232. # only n64 ABI is supported for now
  233. _ostype="${_ostype}abi64"
  234. _cputype=$(get_endianness mips64 '' el)
  235. fi
  236. ;;
  237. ppc)
  238. _cputype=powerpc
  239. ;;
  240. ppc64)
  241. _cputype=powerpc64
  242. ;;
  243. ppc64le)
  244. _cputype=powerpc64le
  245. ;;
  246. s390x)
  247. _cputype=s390x
  248. ;;
  249. riscv64)
  250. _cputype=riscv64gc
  251. ;;
  252. *)
  253. err "unknown CPU type: $_cputype"
  254. esac
  255. # Detect 64-bit linux with 32-bit userland
  256. if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then
  257. case $_cputype in
  258. x86_64)
  259. _cputype=i686
  260. ;;
  261. mips64)
  262. _cputype=$(get_endianness mips '' el)
  263. ;;
  264. powerpc64)
  265. _cputype=powerpc
  266. ;;
  267. aarch64)
  268. _cputype=armv7
  269. if [ "$_ostype" = "linux-android" ]; then
  270. _ostype=linux-androideabi
  271. else
  272. _ostype="${_ostype}eabihf"
  273. fi
  274. ;;
  275. riscv64gc)
  276. err "riscv64 with 32-bit userland unsupported"
  277. ;;
  278. esac
  279. fi
  280. # Detect armv7 but without the CPU features Rust needs in that build,
  281. # and fall back to arm.
  282. # See https://github.com/rust-lang/rustup.rs/issues/587.
  283. if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
  284. if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then
  285. # At least one processor does not have NEON.
  286. _cputype=arm
  287. fi
  288. fi
  289. _arch="${_cputype}-${_ostype}"
  290. RETVAL="$_arch"
  291. }
  292. say() {
  293. printf 'rustup: %s\n' "$1"
  294. }
  295. err() {
  296. say "$1" >&2
  297. exit 1
  298. }
  299. need_cmd() {
  300. if ! check_cmd "$1"; then
  301. err "need '$1' (command not found)"
  302. fi
  303. }
  304. check_cmd() {
  305. command -v "$1" > /dev/null 2>&1
  306. }
  307. assert_nz() {
  308. if [ -z "$1" ]; then err "assert_nz $2"; fi
  309. }
  310. # Run a command that should never fail. If the command fails execution
  311. # will immediately terminate with an error showing the failing
  312. # command.
  313. ensure() {
  314. if ! "$@"; then err "command failed: $*"; fi
  315. }
  316. # This is just for indicating that commands' results are being
  317. # intentionally ignored. Usually, because it's being executed
  318. # as part of error handling.
  319. ignore() {
  320. "$@"
  321. }
  322. # This wraps curl or wget. Try curl first, if not installed,
  323. # use wget instead.
  324. downloader() {
  325. local _dld
  326. local _ciphersuites
  327. if check_cmd curl; then
  328. _dld=curl
  329. elif check_cmd wget; then
  330. _dld=wget
  331. else
  332. _dld='curl or wget' # to be used in error message of need_cmd
  333. fi
  334. if [ "$1" = --check ]; then
  335. need_cmd "$_dld"
  336. elif [ "$_dld" = curl ]; then
  337. get_ciphersuites_for_curl
  338. _ciphersuites="$RETVAL"
  339. if [ -n "$_ciphersuites" ]; then
  340. curl --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2"
  341. else
  342. echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
  343. if ! check_help_for "$3" curl --proto --tlsv1.2; then
  344. echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
  345. curl --silent --show-error --fail --location "$1" --output "$2"
  346. else
  347. curl --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2"
  348. fi
  349. fi
  350. elif [ "$_dld" = wget ]; then
  351. get_ciphersuites_for_wget
  352. _ciphersuites="$RETVAL"
  353. if [ -n "$_ciphersuites" ]; then
  354. wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2"
  355. else
  356. echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
  357. if ! check_help_for "$3" wget --https-only --secure-protocol; then
  358. echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
  359. wget "$1" -O "$2"
  360. else
  361. wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2"
  362. fi
  363. fi
  364. else
  365. err "Unknown downloader" # should not reach here
  366. fi
  367. }
  368. check_help_for() {
  369. local _arch
  370. local _cmd
  371. local _arg
  372. _arch="$1"
  373. shift
  374. _cmd="$1"
  375. shift
  376. case "$_arch" in
  377. # If we're running on OS-X, older than 10.13, then we always
  378. # fail to find these options to force fallback
  379. *darwin*)
  380. if check_cmd sw_vers; then
  381. if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then
  382. # Older than 10.13
  383. echo "Warning: Detected OS X platform older than 10.13"
  384. return 1
  385. fi
  386. fi
  387. ;;
  388. esac
  389. for _arg in "$@"; do
  390. if ! "$_cmd" --help | grep -q -- "$_arg"; then
  391. return 1
  392. fi
  393. done
  394. true # not strictly needed
  395. }
  396. # Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
  397. # if support by local tools is detected. Detection currently supports these curl backends:
  398. # GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
  399. get_ciphersuites_for_curl() {
  400. if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
  401. # user specified custom cipher suites, assume they know what they're doing
  402. RETVAL="$RUSTUP_TLS_CIPHERSUITES"
  403. return
  404. fi
  405. local _openssl_syntax="no"
  406. local _gnutls_syntax="no"
  407. local _backend_supported="yes"
  408. if curl -V | grep -q ' OpenSSL/'; then
  409. _openssl_syntax="yes"
  410. elif curl -V | grep -iq ' LibreSSL/'; then
  411. _openssl_syntax="yes"
  412. elif curl -V | grep -iq ' BoringSSL/'; then
  413. _openssl_syntax="yes"
  414. elif curl -V | grep -iq ' GnuTLS/'; then
  415. _gnutls_syntax="yes"
  416. else
  417. _backend_supported="no"
  418. fi
  419. local _args_supported="no"
  420. if [ "$_backend_supported" = "yes" ]; then
  421. # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
  422. if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then
  423. _args_supported="yes"
  424. fi
  425. fi
  426. local _cs=""
  427. if [ "$_args_supported" = "yes" ]; then
  428. if [ "$_openssl_syntax" = "yes" ]; then
  429. _cs=$(get_strong_ciphersuites_for "openssl")
  430. elif [ "$_gnutls_syntax" = "yes" ]; then
  431. _cs=$(get_strong_ciphersuites_for "gnutls")
  432. fi
  433. fi
  434. RETVAL="$_cs"
  435. }
  436. # Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
  437. # if support by local tools is detected. Detection currently supports these wget backends:
  438. # GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
  439. get_ciphersuites_for_wget() {
  440. if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
  441. # user specified custom cipher suites, assume they know what they're doing
  442. RETVAL="$RUSTUP_TLS_CIPHERSUITES"
  443. return
  444. fi
  445. local _cs=""
  446. if wget -V | grep -q '\-DHAVE_LIBSSL'; then
  447. # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
  448. if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
  449. _cs=$(get_strong_ciphersuites_for "openssl")
  450. fi
  451. elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
  452. # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
  453. if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
  454. _cs=$(get_strong_ciphersuites_for "gnutls")
  455. fi
  456. fi
  457. RETVAL="$_cs"
  458. }
  459. # Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2
  460. # excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad
  461. # DH params often found on servers (see RFC 7919). Sequence matches or is
  462. # similar to Firefox 68 ESR with weak cipher suites disabled via about:config.
  463. # $1 must be openssl or gnutls.
  464. get_strong_ciphersuites_for() {
  465. if [ "$1" = "openssl" ]; then
  466. # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
  467. echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
  468. elif [ "$1" = "gnutls" ]; then
  469. # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
  470. # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
  471. echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM"
  472. fi
  473. }
  474. main "$@" || exit 1