Merge "Add script to dl and extract verible tarball"
diff --git a/fetch-rust-toolchain.sh b/fetch-rust-toolchain.sh
new file mode 100755
index 0000000..7aed0e2
--- /dev/null
+++ b/fetch-rust-toolchain.sh
@@ -0,0 +1,178 @@
+#!/bin/bash
+#
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Fetches the rust toolchain from cloud storage
+
+PUBLIC_ARTIFACTS_PATH="gs://shodan-public-artifacts"
+PUBLIC_ARTIFACTS_URL="https://storage.googleapis.com/shodan-public-artifacts"
+
+function die {
+ echo "$@" >/dev/stderr
+ exit 1
+}
+
+function try {
+ echo "$@"
+ "$@" || die "Failed to execute '$@': exited with return code $?"
+}
+
+function in-dir {
+ local directory="$1"; shift
+ local exitcode=""
+
+ echo "Entering directory ${directory}"
+ (cd "$directory" && "$@")
+ exitcode="$?"
+ echo "Leaving directory ${directory}"
+
+ if [[ "${exitcode}" != "0" ]]; then
+ die "Failed to execute '$@': exited with return code ${exitcode}"
+ fi
+}
+
+function list-tarballs {
+ if [[ "$EUID" == 0 ]]; then
+ die "This script must NOT be run as root."
+ fi
+ if ! hash gsutil 2>/dev/null; then
+ die "Google cloud SDK is not installed."
+ fi
+
+ echo "Available tarballs:"
+ echo
+ gsutil ls "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain*.tar.xz"
+}
+
+function generate-tarball-name {
+ local version="$1"; shift
+ if [[ -z "${version}" ]]; then
+ die "No version specified."
+ fi
+
+ echo "rust_toolchain_${version}.tar.xz"
+}
+
+function get-original-name {
+ local tarball="$1"; shift
+ cat "${tarball}.sha256sum" |awk '{ print $2 }'
+}
+
+function download-tarball {
+ local version="$1"; shift
+ local tarball="$(generate-tarball-name ${version})"
+ local checksum="${tarball}.sha256sum"
+
+ try mkdir -p "${OUT}"
+
+ try wget -O "${OUT}/${tarball}" "${PUBLIC_ARTIFACTS_URL}/${tarball}"
+ try wget -O "${OUT}/${checksum}" "${PUBLIC_ARTIFACTS_URL}/${checksum}"
+
+ # Workaround the fact that we use the datestamped version of the filename
+ # at sha256sum creation time. IOW, "latest" is a symbolic name to make
+ # fetching easier, so we have to rename the tarball to the original name.
+ # Conveniently, this also allows us to determine which tarball is currently
+ # set as the latest in storage.
+ if [[ "${version}" == "latest" ]]; then
+ local original_name=$(get-original-name "${OUT}/${tarball}")
+ try mv "${OUT}/${tarball}" "${OUT}/${original_name}"
+ try mv "${OUT}/${checksum}" "${OUT}/${original_name}.sha256sum"
+ tarball="${original_name}"
+ checksum="${original_name}.sha256sum"
+ fi
+
+ try in-dir "${OUT}" sha256sum -c "${checksum}"
+ try mkdir -p "${CACHE}"
+ try tar -C "${CACHE}" -xf "${OUT}/${tarball}"
+}
+
+function show-usage {
+ cat >/dev/stderr <<EOF
+Usage: fetch-rust-toolchain.sh <-d|-l> [-v <date|latest>]
+
+Fetches, verifies, and untars Rust toolchain tarballs from upstram cloud storage
+into cache/.
+
+Options:
+ -l | --list List available rust tarballs. Note: this requires the
+ Google Cloud SDK to be installed and logged in.
+ -d | --download Download a tarball. If -v is not provided, assumes
+ "latest".
+ -v <date|latest> | --version <date|latest>
+ Download either the tarball of the specified version, or
+ the latest one from upstream storage. If this option is
+ not specified, defaults to "latest".
+EOF
+}
+
+function main {
+ local usage="Usage: install-rust-toolchain.sh [-d|-l|-v <datestamp>]"
+ local args=$(getopt -o hdlv: \
+ --long help,download,list:,version: \
+ -n fetch-rust-toolchain.sh -- "$@")
+ eval set -- "$args"
+
+ local version="latest"
+ local mode=""
+
+ while true; do
+ case "$1" in
+ -d|--download)
+ mode="download"
+ shift
+ ;;
+
+ -l|--list)
+ mode="list"
+ shift
+ ;;
+
+ -v|--version)
+ version="$2"
+ shift
+ shift
+ ;;
+
+ --)
+ shift
+ break
+ ;;
+
+ *)
+ die "${usage}"
+ ;;
+ esac
+ done
+
+ case "${mode}" in
+ list)
+ list-tarballs
+ ;;
+
+ download)
+ download-tarball "${version}"
+ ;;
+
+ *)
+ show-usage
+ ;;
+ esac
+}
+
+if [[ -z "${ROOTDIR}" || -z "${RUSTDIR}" ]]; then
+ die "Source build/setup.sh first"
+fi
+
+main "$@"
diff --git a/install-rust-toolchain.sh b/install-rust-toolchain.sh
index b524aca..5a0887c 100755
--- a/install-rust-toolchain.sh
+++ b/install-rust-toolchain.sh
@@ -1,29 +1,132 @@
-#! /bin/bash
+#!/bin/bash
+#
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
# Install the rust toolchain to specified version and variant
-if [[ "$#" -ne 3 || $1 == "--help" ]]; then
- echo "Usage: install-rust-toolchain.sh <rust dir> <build version|rust-toolchain path> <target>"
- exit 1
+RUSTUP="${RUSTDIR}/bin/rustup"
+
+function die {
+ echo "$@" >/dev/stderr
+ exit 1
+}
+
+function try {
+ echo "$@"
+ "$@" || die "Failed to execute '$@': exited with return code $?"
+}
+
+function in-dir {
+ local directory="$1"; shift
+ local exitcode=""
+
+ echo "Entering directory ${directory}"
+ (cd "$directory" && "$@")
+ exitcode="$?"
+ echo "Leaving directory ${directory}"
+
+ if [[ "${exitcode}" != "0" ]]; then
+ die "Failed to execute '$@': exited with return code ${exitcode}"
+ fi
+}
+
+function main {
+ local usage="Usage: install-rust-toolchain.sh [-v <version> | -p <project-dir>] <target-to-install>"
+ local args=$(getopt -o hv:p: \
+ --long help,version:,project: \
+ -n install-rust-toolchain.sh -- "$@")
+ eval set -- "$args"
+
+ local version=""
+ local project_dir=""
+
+ while true; do
+ case "$1" in
+ -v|--version)
+ version="$2"
+ shift
+ shift
+ ;;
+
+ -p|--project)
+ project_dir="$2"
+ shift
+ shift
+ ;;
+
+ -h|--help)
+ die "$usage"
+ ;;
+
+ --)
+ shift
+ break
+ ;;
+ esac
+ done
+
+ if [[ ! -z "${version}" && ! -z "${project_dir}" ]]; then
+ echo "${usage}"
+ echo
+ die "-p and -v are mutually exclusive."
+ fi
+
+ local target="$1"; shift
+ try mkdir -p "${RUSTDIR}"
+
+ if [[ ! -f "${RUSTUP}" ]]; then
+ local yesorno=""
+ echo "========================================================================"
+ echo "Rustup not found locally -- do you want to install it?"
+ echo
+ echo "Please verify that you understand this will fetch binaries"
+ echo "from potentially untrusted sources. Googlers *must* use"
+ echo "internally verified builds of the rust compiler toolchains from"
+ echo "the internal toolchain tarball repository instead. Do not use this"
+ echo "tool to install Rust locally!"
+ echo
+ read -p "Type YES (in all caps) to proceed: " yesorno
+
+ [[ "${yesorno}" != "YES" ]] && die "User did not indicate agreement."
+ try "${ROOTDIR}/scripts/thirdparty/rustup-install.sh" -y
+ fi
+
+ if [[ -f "${project_dir}" ]]; then
+ # The project specifies its own version of the rust toolchain, and the
+ # user is pointing to its specification files, so let rustup use that to
+ # install the needed toolchain.
+
+ local project_dir=$(dirname $(realpath "${project_dir}"))
+ echo "Installing the rust toolchain for project ${project_dir}..."
+ try in-dir "${project_dir}" "${RUSTUP}" target add "${target}"
+ elif [[ ! -z "${version}" ]]; then
+ # We're being asked to install a specific version of the rust toolchain.
+
+ echo "Installing rust toolchain ${version} for target ${target}..."
+ try "${RUSTUP}" "+${version}" target add "${target}"
+ else
+ die "One of -p or -v must be specified."
+ fi
+}
+
+if [[ "$EUID" == 0 ]]; then
+ die "This script must NOT be run as root."
fi
-RUST_DIR=$1
-
-BUILD_TOOLCHAIN=$2
-TARGET=$3
-
-RUSTUP_BIN="${RUST_DIR}/bin/rustup"
-
-mkdir -p "${RUST_DIR}"
-
-if [[ ! -f "${RUSTUP_BIN}" ]]; then
- bash -c 'curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path'
+if [[ -z "${ROOTDIR}" || -z "${RUSTDIR}" ]]; then
+ die "Source build/setup.sh first"
fi
-if [[ -f "${BUILD_TOOLCHAIN}" ]]; then
- BUILD_PROJECT=$(dirname $(realpath "${BUILD_TOOLCHAIN}"))
- echo "Build rust toolchain specified for project ${BUILD_PROJECT}..."
- cd "${BUILD_PROJECT}"; "${RUSTUP_BIN}" target add "${TARGET}"
-else
- echo "Build specified toolchain ${BUILD_TOOLCHAIN}..."
- "${RUSTUP_BIN}" "+${BUILD_TOOLCHAIN}" target add "${TARGET}"
-fi
+main "$@"
diff --git a/manage-rust-toolchain.sh b/manage-rust-toolchain.sh
new file mode 100755
index 0000000..3a700f2
--- /dev/null
+++ b/manage-rust-toolchain.sh
@@ -0,0 +1,208 @@
+#!/bin/bash
+#
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build a rust toolchain tarball for download use later.
+
+PUBLIC_ARTIFACTS_PATH="gs://shodan-public-artifacts"
+
+function die {
+ echo "$@" >/dev/stderr
+ exit 1
+}
+
+function try {
+ echo "$@"
+ "$@" || die "Failed to execute '$@': exited with return code $?"
+}
+
+function show-usage {
+ cat >/dev/stderr <<EOF
+Usage: manage-rust-toolchain.sh [-c|-u|-p <date>]
+
+Creates, uploads, and promotes Rust toolchain tarballs from toolchain installs
+on local disk in cache/.
+
+Options:
+ -l | --list List available rust tarballs.
+ -c | --create Create a new toolchain tarball and sha256sum from files in
+ cache/.
+ -u | --upload Upload the existing toolchain tarball to Google storage.
+ Note: requires the Google Cloud SDK to be installed and
+ logged in to function.
+ -p <date> | --promote <date>
+ Promote the given date stamp tarball to latest.
+EOF
+ exit 1
+}
+
+function generate-tarball-name {
+ local datestamp=$(date -I)
+ echo "rust_toolchain_${datestamp}.tar.xz"
+}
+
+function create-tarball {
+ if [[ ! -d "${RUSTDIR}" ]]; then
+ die "No rust toolchain installed at ${RUSTDIR}. Please install it first, and try again."
+ fi
+
+ local tarball="$(generate-tarball-name)"
+
+ if [[ -f "${OUT}/${tarball}" ]]; then
+ die "Tarball ${tarball} already exists -- cowardly refusing to overwrite it."
+ fi
+
+ mkdir -p "${OUT}"
+
+ echo "Creating tarball in ${OUT}/${tarball}..."
+ tar -C "${ROOTDIR}/cache" -c -f - rust_toolchain \
+ |xz -T0 -9 \
+ > "${OUT}/${tarball}"
+
+ if [[ "$?" != 0 ]]; then
+ die "Couldn't create tarball."
+ fi
+
+ echo "Generating sha256sums..."
+ (cd "${OUT}" && sha256sum "${tarball}") > "${OUT}/${tarball}.sha256sum"
+
+ if [[ "$?" != 0 ]]; then
+ die "Couldn't create sha256sum checksum file."
+ fi
+
+ echo "Verifying sha256sum is valid..."
+ (cd "${OUT}" && sha256sum -c "${tarball}.sha256sum")
+
+ if [[ "$?" != 0 ]]; then
+ die "Couldn't verify sha256sum!"
+ fi
+}
+
+function list-tarballs {
+ echo "Available tarballs:"
+ echo
+ gsutil ls "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain*.tar.xz"
+}
+
+function upload-tarball {
+ local tarball="$(generate-tarball-name)"
+
+ echo "Uploading tarball..."
+ try gsutil cp "${OUT}/${tarball}" "${PUBLIC_ARTIFACTS_PATH}/${tarball}"
+ try gsutil cp "${OUT}/${tarball}.sha256sum" "${PUBLIC_ARTIFACTS_PATH}/${tarball}.sha256sum"
+}
+
+function promote-tarball {
+ local promote_date="$1"; shift
+
+ echo "Removing old latest toolchain..."
+ try gsutil rm \
+ "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain_latest.tar.xz"
+ try gsutil rm \
+ "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain_latest.tar.xz.sha256sum"
+
+ echo "Promoting tarball rust_toolchain_${promote_date}.tar.xz to rust_toolchain_latest.tar.xz"
+ try gsutil cp \
+ "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain_${promote_date}.tar.xz" \
+ "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain_latest.tar.xz"
+ try gsutil cp \
+ "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain_${promote_date}.tar.xz.sha256sum" \
+ "${PUBLIC_ARTIFACTS_PATH}/rust_toolchain_latest.tar.xz.sha256sum"
+}
+
+function main {
+ local usage="Usage: manage-rust-toolchain.sh [-l|-c|-u|-p <date>]"
+ local args=$(getopt -o h,l,c,u,p: --long help,list,create,upload,promote: \
+ -n manage-rust-toolchain.sh -- "$@")
+ eval set -- "$args"
+
+ local mode=""
+ local promote_date=""
+
+ while true; do
+ case "$1" in
+ -l|--list)
+ mode="list"
+ shift
+ ;;
+
+ -c|--create)
+ mode="create-tarball"
+ shift
+ ;;
+
+ -u|--upload)
+ mode="upload"
+ shift
+ ;;
+
+ -p|--promote)
+ mode="promote"
+ promote_date="$2"
+ shift
+ shift
+ ;;
+
+ -h|--help)
+ show-usage
+ ;;
+
+ --)
+ shift
+ break
+ ;;
+
+ *)
+ die "Unknown option '$1'; maybe try --help?"
+ ;;
+ esac
+ done
+
+ case "${mode}" in
+ list)
+ list-tarballs
+ ;;
+
+ create-tarball)
+ create-tarball
+ ;;
+
+ upload)
+ upload-tarball
+ ;;
+
+ promote)
+ promote-tarball "${promote_date}"
+ ;;
+
+ *)
+ show-usage
+ ;;
+ esac
+}
+
+if [[ "$EUID" == 0 ]]; then
+ die "This script must NOT be run as root."
+fi
+
+if [[ -z "${ROOTDIR}" || -z "${RUSTDIR}" ]]; then
+ die "Source build/setup.sh first"
+fi
+
+if ! hash gsutil 2>/dev/null; then
+ die "This script requires the Google SDK to be installed."
+fi
+
+main "$@"
diff --git a/thirdparty/rustup-install.sh b/thirdparty/rustup-install.sh
new file mode 100755
index 0000000..a4a79a2
--- /dev/null
+++ b/thirdparty/rustup-install.sh
@@ -0,0 +1,662 @@
+#!/bin/sh
+# shellcheck shell=dash
+
+# This is just a little script that can be downloaded from the internet to
+# install rustup. It just does platform detection, downloads the installer
+# and runs it.
+
+# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
+# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
+
+if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then
+ # The version of ksh93 that ships with many illumos systems does not
+ # support the "local" extension. Print a message rather than fail in
+ # subtle ways later on:
+ echo 'rustup does not work with this ksh93 version; please try bash!' >&2
+ exit 1
+fi
+
+
+set -u
+
+# If RUSTUP_UPDATE_ROOT is unset or empty, default it.
+RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}"
+
+#XXX: If you change anything here, please make the same changes in setup_mode.rs
+usage() {
+ cat 1>&2 <<EOF
+rustup-init 1.24.3 (c1c769109 2021-05-31)
+The installer for rustup
+
+USAGE:
+ rustup-init [FLAGS] [OPTIONS]
+
+FLAGS:
+ -v, --verbose Enable verbose output
+ -q, --quiet Disable progress output
+ -y Disable confirmation prompt.
+ --no-modify-path Don't configure the PATH environment variable
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --default-host <default-host> Choose a default host triple
+ --default-toolchain <default-toolchain> Choose a default toolchain to install
+ --default-toolchain none Do not install any toolchains
+ --profile [minimal|default|complete] Choose a profile
+ -c, --component <components>... Component name to also install
+ -t, --target <targets>... Target name to also install
+EOF
+}
+
+main() {
+ downloader --check
+ need_cmd uname
+ need_cmd mktemp
+ need_cmd chmod
+ need_cmd mkdir
+ need_cmd rm
+ need_cmd rmdir
+
+ get_architecture || return 1
+ local _arch="$RETVAL"
+ assert_nz "$_arch" "arch"
+
+ local _ext=""
+ case "$_arch" in
+ *windows*)
+ _ext=".exe"
+ ;;
+ esac
+
+ local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}"
+
+ local _dir
+ _dir="$(ensure mktemp -d)"
+ local _file="${_dir}/rustup-init${_ext}"
+
+ local _ansi_escapes_are_valid=false
+ if [ -t 2 ]; then
+ if [ "${TERM+set}" = 'set' ]; then
+ case "$TERM" in
+ xterm*|rxvt*|urxvt*|linux*|vt*)
+ _ansi_escapes_are_valid=true
+ ;;
+ esac
+ fi
+ fi
+
+ # check if we have to use /dev/tty to prompt the user
+ local need_tty=yes
+ for arg in "$@"; do
+ case "$arg" in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -y)
+ # user wants to skip the prompt -- we don't need /dev/tty
+ need_tty=no
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ if $_ansi_escapes_are_valid; then
+ printf "\33[1minfo:\33[0m downloading installer\n" 1>&2
+ else
+ printf '%s\n' 'info: downloading installer' 1>&2
+ fi
+
+ ensure mkdir -p "$_dir"
+ ensure downloader "$_url" "$_file" "$_arch"
+ ensure chmod u+x "$_file"
+ if [ ! -x "$_file" ]; then
+ printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
+ printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init${_ext}." 1>&2
+ exit 1
+ fi
+
+ if [ "$need_tty" = "yes" ]; then
+ # The installer is going to want to ask for confirmation by
+ # reading stdin. This script was piped into `sh` though and
+ # doesn't have stdin to pass to its children. Instead we're going
+ # to explicitly connect /dev/tty to the installer's stdin.
+ if [ ! -t 1 ]; then
+ err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
+ fi
+
+ ignore "$_file" "$@" < /dev/tty
+ else
+ ignore "$_file" "$@"
+ fi
+
+ local _retval=$?
+
+ ignore rm "$_file"
+ ignore rmdir "$_dir"
+
+ return "$_retval"
+}
+
+check_proc() {
+ # Check for /proc by looking for the /proc/self/exe link
+ # This is only run on Linux
+ if ! test -L /proc/self/exe ; then
+ err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc."
+ fi
+}
+
+get_bitness() {
+ need_cmd head
+ # Architecture detection without dependencies beyond coreutils.
+ # ELF files start out "\x7fELF", and the following byte is
+ # 0x01 for 32-bit and
+ # 0x02 for 64-bit.
+ # The printf builtin on some shells like dash only supports octal
+ # escape sequences, so we use those.
+ local _current_exe_head
+ _current_exe_head=$(head -c 5 /proc/self/exe )
+ if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then
+ echo 32
+ elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then
+ echo 64
+ else
+ err "unknown platform bitness"
+ fi
+}
+
+is_host_amd64_elf() {
+ need_cmd head
+ need_cmd tail
+ # ELF e_machine detection without dependencies beyond coreutils.
+ # Two-byte field at offset 0x12 indicates the CPU,
+ # but we're interested in it being 0x3E to indicate amd64, or not that.
+ local _current_exe_machine
+ _current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1)
+ [ "$_current_exe_machine" = "$(printf '\076')" ]
+}
+
+get_endianness() {
+ local cputype=$1
+ local suffix_eb=$2
+ local suffix_el=$3
+
+ # detect endianness without od/hexdump, like get_bitness() does.
+ need_cmd head
+ need_cmd tail
+
+ local _current_exe_endianness
+ _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)"
+ if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then
+ echo "${cputype}${suffix_el}"
+ elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then
+ echo "${cputype}${suffix_eb}"
+ else
+ err "unknown platform endianness"
+ fi
+}
+
+get_architecture() {
+ local _ostype _cputype _bitness _arch _clibtype
+ _ostype="$(uname -s)"
+ _cputype="$(uname -m)"
+ _clibtype="gnu"
+
+ if [ "$_ostype" = Linux ]; then
+ if [ "$(uname -o)" = Android ]; then
+ _ostype=Android
+ fi
+ if ldd --version 2>&1 | grep -q 'musl'; then
+ _clibtype="musl"
+ fi
+ fi
+
+ if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
+ # Darwin `uname -m` lies
+ if sysctl hw.optional.x86_64 | grep -q ': 1'; then
+ _cputype=x86_64
+ fi
+ fi
+
+ if [ "$_ostype" = SunOS ]; then
+ # Both Solaris and illumos presently announce as "SunOS" in "uname -s"
+ # so use "uname -o" to disambiguate. We use the full path to the
+ # system uname in case the user has coreutils uname first in PATH,
+ # which has historically sometimes printed the wrong value here.
+ if [ "$(/usr/bin/uname -o)" = illumos ]; then
+ _ostype=illumos
+ fi
+
+ # illumos systems have multi-arch userlands, and "uname -m" reports the
+ # machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86
+ # systems. Check for the native (widest) instruction set on the
+ # running kernel:
+ if [ "$_cputype" = i86pc ]; then
+ _cputype="$(isainfo -n)"
+ fi
+ fi
+
+ case "$_ostype" in
+
+ Android)
+ _ostype=linux-android
+ ;;
+
+ Linux)
+ check_proc
+ _ostype=unknown-linux-$_clibtype
+ _bitness=$(get_bitness)
+ ;;
+
+ FreeBSD)
+ _ostype=unknown-freebsd
+ ;;
+
+ NetBSD)
+ _ostype=unknown-netbsd
+ ;;
+
+ DragonFly)
+ _ostype=unknown-dragonfly
+ ;;
+
+ Darwin)
+ _ostype=apple-darwin
+ ;;
+
+ illumos)
+ _ostype=unknown-illumos
+ ;;
+
+ MINGW* | MSYS* | CYGWIN*)
+ _ostype=pc-windows-gnu
+ ;;
+
+ *)
+ err "unrecognized OS type: $_ostype"
+ ;;
+
+ esac
+
+ case "$_cputype" in
+
+ i386 | i486 | i686 | i786 | x86)
+ _cputype=i686
+ ;;
+
+ xscale | arm)
+ _cputype=arm
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ fi
+ ;;
+
+ armv6l)
+ _cputype=arm
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ else
+ _ostype="${_ostype}eabihf"
+ fi
+ ;;
+
+ armv7l | armv8l)
+ _cputype=armv7
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ else
+ _ostype="${_ostype}eabihf"
+ fi
+ ;;
+
+ aarch64 | arm64)
+ _cputype=aarch64
+ ;;
+
+ x86_64 | x86-64 | x64 | amd64)
+ _cputype=x86_64
+ ;;
+
+ mips)
+ _cputype=$(get_endianness mips '' el)
+ ;;
+
+ mips64)
+ if [ "$_bitness" -eq 64 ]; then
+ # only n64 ABI is supported for now
+ _ostype="${_ostype}abi64"
+ _cputype=$(get_endianness mips64 '' el)
+ fi
+ ;;
+
+ ppc)
+ _cputype=powerpc
+ ;;
+
+ ppc64)
+ _cputype=powerpc64
+ ;;
+
+ ppc64le)
+ _cputype=powerpc64le
+ ;;
+
+ s390x)
+ _cputype=s390x
+ ;;
+ riscv64)
+ _cputype=riscv64gc
+ ;;
+ *)
+ err "unknown CPU type: $_cputype"
+
+ esac
+
+ # Detect 64-bit linux with 32-bit userland
+ if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then
+ case $_cputype in
+ x86_64)
+ if [ -n "${RUSTUP_CPUTYPE:-}" ]; then
+ _cputype="$RUSTUP_CPUTYPE"
+ else {
+ # 32-bit executable for amd64 = x32
+ if is_host_amd64_elf; then {
+ echo "This host is running an x32 userland; as it stands, x32 support is poor," 1>&2
+ echo "and there isn't a native toolchain -- you will have to install" 1>&2
+ echo "multiarch compatibility with i686 and/or amd64, then select one" 1>&2
+ echo "by re-running this script with the RUSTUP_CPUTYPE environment variable" 1>&2
+ echo "set to i686 or x86_64, respectively." 1>&2
+ echo 1>&2
+ echo "You will be able to add an x32 target after installation by running" 1>&2
+ echo " rustup target add x86_64-unknown-linux-gnux32" 1>&2
+ exit 1
+ }; else
+ _cputype=i686
+ fi
+ }; fi
+ ;;
+ mips64)
+ _cputype=$(get_endianness mips '' el)
+ ;;
+ powerpc64)
+ _cputype=powerpc
+ ;;
+ aarch64)
+ _cputype=armv7
+ if [ "$_ostype" = "linux-android" ]; then
+ _ostype=linux-androideabi
+ else
+ _ostype="${_ostype}eabihf"
+ fi
+ ;;
+ riscv64gc)
+ err "riscv64 with 32-bit userland unsupported"
+ ;;
+ esac
+ fi
+
+ # Detect armv7 but without the CPU features Rust needs in that build,
+ # and fall back to arm.
+ # See https://github.com/rust-lang/rustup.rs/issues/587.
+ if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
+ if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then
+ # At least one processor does not have NEON.
+ _cputype=arm
+ fi
+ fi
+
+ _arch="${_cputype}-${_ostype}"
+
+ RETVAL="$_arch"
+}
+
+say() {
+ printf 'rustup: %s\n' "$1"
+}
+
+err() {
+ say "$1" >&2
+ exit 1
+}
+
+need_cmd() {
+ if ! check_cmd "$1"; then
+ err "need '$1' (command not found)"
+ fi
+}
+
+check_cmd() {
+ command -v "$1" > /dev/null 2>&1
+}
+
+assert_nz() {
+ if [ -z "$1" ]; then err "assert_nz $2"; fi
+}
+
+# Run a command that should never fail. If the command fails execution
+# will immediately terminate with an error showing the failing
+# command.
+ensure() {
+ if ! "$@"; then err "command failed: $*"; fi
+}
+
+# This is just for indicating that commands' results are being
+# intentionally ignored. Usually, because it's being executed
+# as part of error handling.
+ignore() {
+ "$@"
+}
+
+# This wraps curl or wget. Try curl first, if not installed,
+# use wget instead.
+downloader() {
+ local _dld
+ local _ciphersuites
+ local _err
+ local _status
+ if check_cmd curl; then
+ _dld=curl
+ elif check_cmd wget; then
+ _dld=wget
+ else
+ _dld='curl or wget' # to be used in error message of need_cmd
+ fi
+
+ if [ "$1" = --check ]; then
+ need_cmd "$_dld"
+ elif [ "$_dld" = curl ]; then
+ get_ciphersuites_for_curl
+ _ciphersuites="$RETVAL"
+ if [ -n "$_ciphersuites" ]; then
+ _err=$(curl --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1)
+ _status=$?
+ else
+ echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
+ if ! check_help_for "$3" curl --proto --tlsv1.2; then
+ echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
+ _err=$(curl --silent --show-error --fail --location "$1" --output "$2" 2>&1)
+ _status=$?
+ else
+ _err=$(curl --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2" 2>&1)
+ _status=$?
+ fi
+ fi
+ if [ -n "$_err" ]; then
+ echo "$_err" >&2
+ if echo "$_err" | grep -q 404$; then
+ err "installer for platform '$3' not found, this may be unsupported"
+ fi
+ fi
+ return $_status
+ elif [ "$_dld" = wget ]; then
+ get_ciphersuites_for_wget
+ _ciphersuites="$RETVAL"
+ if [ -n "$_ciphersuites" ]; then
+ _err=$(wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2" 2>&1)
+ _status=$?
+ else
+ echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
+ if ! check_help_for "$3" wget --https-only --secure-protocol; then
+ echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
+ _err=$(wget "$1" -O "$2" 2>&1)
+ _status=$?
+ else
+ _err=$(wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2" 2>&1)
+ _status=$?
+ fi
+ fi
+ if [ -n "$_err" ]; then
+ echo "$_err" >&2
+ if echo "$_err" | grep -q ' 404 Not Found$'; then
+ err "installer for platform '$3' not found, this may be unsupported"
+ fi
+ fi
+ return $_status
+ else
+ err "Unknown downloader" # should not reach here
+ fi
+}
+
+check_help_for() {
+ local _arch
+ local _cmd
+ local _arg
+ _arch="$1"
+ shift
+ _cmd="$1"
+ shift
+
+ local _category
+ if "$_cmd" --help | grep -q 'For all options use the manual or "--help all".'; then
+ _category="all"
+ else
+ _category=""
+ fi
+
+ case "$_arch" in
+
+ *darwin*)
+ if check_cmd sw_vers; then
+ case $(sw_vers -productVersion) in
+ 10.*)
+ # If we're running on macOS, older than 10.13, then we always
+ # fail to find these options to force fallback
+ if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then
+ # Older than 10.13
+ echo "Warning: Detected macOS platform older than 10.13"
+ return 1
+ fi
+ ;;
+ 11.*)
+ # We assume Big Sur will be OK for now
+ ;;
+ *)
+ # Unknown product version, warn and continue
+ echo "Warning: Detected unknown macOS major version: $(sw_vers -productVersion)"
+ echo "Warning TLS capabilities detection may fail"
+ ;;
+ esac
+ fi
+ ;;
+
+ esac
+
+ for _arg in "$@"; do
+ if ! "$_cmd" --help $_category | grep -q -- "$_arg"; then
+ return 1
+ fi
+ done
+
+ true # not strictly needed
+}
+
+# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
+# if support by local tools is detected. Detection currently supports these curl backends:
+# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
+get_ciphersuites_for_curl() {
+ if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
+ # user specified custom cipher suites, assume they know what they're doing
+ RETVAL="$RUSTUP_TLS_CIPHERSUITES"
+ return
+ fi
+
+ local _openssl_syntax="no"
+ local _gnutls_syntax="no"
+ local _backend_supported="yes"
+ if curl -V | grep -q ' OpenSSL/'; then
+ _openssl_syntax="yes"
+ elif curl -V | grep -iq ' LibreSSL/'; then
+ _openssl_syntax="yes"
+ elif curl -V | grep -iq ' BoringSSL/'; then
+ _openssl_syntax="yes"
+ elif curl -V | grep -iq ' GnuTLS/'; then
+ _gnutls_syntax="yes"
+ else
+ _backend_supported="no"
+ fi
+
+ local _args_supported="no"
+ if [ "$_backend_supported" = "yes" ]; then
+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
+ if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then
+ _args_supported="yes"
+ fi
+ fi
+
+ local _cs=""
+ if [ "$_args_supported" = "yes" ]; then
+ if [ "$_openssl_syntax" = "yes" ]; then
+ _cs=$(get_strong_ciphersuites_for "openssl")
+ elif [ "$_gnutls_syntax" = "yes" ]; then
+ _cs=$(get_strong_ciphersuites_for "gnutls")
+ fi
+ fi
+
+ RETVAL="$_cs"
+}
+
+# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
+# if support by local tools is detected. Detection currently supports these wget backends:
+# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
+get_ciphersuites_for_wget() {
+ if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
+ # user specified custom cipher suites, assume they know what they're doing
+ RETVAL="$RUSTUP_TLS_CIPHERSUITES"
+ return
+ fi
+
+ local _cs=""
+ if wget -V | grep -q '\-DHAVE_LIBSSL'; then
+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
+ if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
+ _cs=$(get_strong_ciphersuites_for "openssl")
+ fi
+ elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
+ # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
+ if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
+ _cs=$(get_strong_ciphersuites_for "gnutls")
+ fi
+ fi
+
+ RETVAL="$_cs"
+}
+
+# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2
+# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad
+# DH params often found on servers (see RFC 7919). Sequence matches or is
+# similar to Firefox 68 ESR with weak cipher suites disabled via about:config.
+# $1 must be openssl or gnutls.
+get_strong_ciphersuites_for() {
+ if [ "$1" = "openssl" ]; then
+ # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
+ 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"
+ elif [ "$1" = "gnutls" ]; then
+ # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
+ # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
+ 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"
+ fi
+}
+
+main "$@" || exit 1