rustup-init.sh 16 KB

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