1111# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
1212# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
1313
14- # This script is based off https://github.com/rust-lang/rustup/blob/f8d7b3baba7a63237cb2b82ef49a68a37dd0633c/rustup-init.sh
14+ # This script is based off https://github.com/rust-lang/rustup/blob/2d429e8e172d5854b6dd7244ecbb0dc3da88a678/rustup-init.sh
15+
16+ # Some versions of ksh have no `local` keyword. Alias it to `typeset`, but
17+ # beware this makes variables global with f()-style function syntax in ksh93.
18+ # mksh has this alias by default.
19+ has_local () {
20+ # shellcheck disable=SC2034 # deliberately unused
21+ local _has_local
22+ }
1523
16- if [ " $KSH_VERSION " = ' Version JM 93t+ 2010-03-05' ]; then
17- # The version of ksh93 that ships with many illumos systems does not
18- # support the "local" extension. Print a message rather than fail in
19- # subtle ways later on:
20- echo ' nix-installer does not work with this ksh93 version; please try bash!' >&2
21- exit 1
22- fi
24+ has_local 2> /dev/null || alias local=typeset
2325
26+ is_zsh () {
27+ [ -n " ${ZSH_VERSION-} " ]
28+ }
2429
2530set -u
2631
@@ -84,18 +89,14 @@ main() {
8489 need_tty=no
8590 fi
8691
87- if $_ansi_escapes_are_valid ; then
88- printf " \33[1minfo:\33[0m downloading installer \33[4m%s\33[0m\n" " $_url " 1>&2
89- else
90- printf ' info: downloading installer (%s)\n' " $_url " 1>&2
91- fi
92+ say ' downloading installer'
9293
9394 ensure mkdir -p " $_dir "
9495 ensure downloader " $_url " " $_file " " $_arch "
9596 ensure chmod u+x " $_file "
9697 if [ ! -x " $_file " ]; then
97- printf ' %s\n ' " Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
98- printf ' %s\n ' " Please copy the file to a location where you can execute binaries and run ./nix-installer${_ext} ." 1>&2
98+ err " Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
99+ err " Please copy the file to a location where you can execute binaries and run ./nix-installer${_ext} ." 1>&2
99100 exit 1
100101 fi
101102
@@ -106,6 +107,7 @@ main() {
106107 # to explicitly connect /dev/tty to the installer's stdin.
107108 if [ ! -t 1 ]; then
108109 err " Unable to run interactively. Run with --no-confirm to accept defaults, --help for additional options"
110+ exit 1;
109111 fi
110112
111113 ignore " $_file " " $@ " < /dev/tty
@@ -121,12 +123,23 @@ main() {
121123 return " $_retval "
122124}
123125
124- check_proc () {
125- # Check for /proc by looking for the /proc/self/exe link
126+ get_current_exe () {
127+ # Returns the executable used for system architecture detection
126128 # This is only run on Linux
127- if ! test -L /proc/self/exe ; then
128- err " fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc."
129+ local _current_exe
130+ if test -L /proc/self/exe ; then
131+ _current_exe=/proc/self/exe
132+ else
133+ warn " Unable to find /proc/self/exe. System architecture detection might be inaccurate."
134+ if test -n " $SHELL " ; then
135+ _current_exe=$SHELL
136+ else
137+ need_cmd /bin/sh
138+ _current_exe=/bin/sh
139+ fi
140+ warn " Falling back to $_current_exe ."
129141 fi
142+ echo " $_current_exe "
130143}
131144
132145get_architecture () {
@@ -138,9 +151,6 @@ get_architecture() {
138151 if [ " $( uname -o) " = Android ]; then
139152 _ostype=Android
140153 fi
141- if ldd --version 2>&1 | grep -q ' musl' ; then
142- _clibtype=" musl"
143- fi
144154 fi
145155
146156 if [ " $_ostype " = Darwin ]; then
@@ -155,7 +165,7 @@ get_architecture() {
155165 # See: <https://support.apple.com/en-us/HT208436>
156166
157167 # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
158- if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ' : 1' ; then
168+ if ( sysctl hw.optional.x86_64 2> /dev/null || true) | grep -q ' : 1' ; then
159169 _cputype=x86_64
160170 fi
161171 elif [ " $_cputype " = x86_64 ]; then
@@ -164,7 +174,7 @@ get_architecture() {
164174 # Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries.
165175
166176 # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
167- if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ' : 1' ; then
177+ if ( sysctl hw.optional.arm64 2> /dev/null || true) | grep -q ' : 1' ; then
168178 _cputype=arm64
169179 fi
170180 fi
@@ -188,9 +198,10 @@ get_architecture() {
188198 fi
189199 fi
190200
201+ local _current_exe
191202 case " $_ostype " in
192203 Linux)
193- check_proc
204+ _current_exe= $( get_current_exe )
194205 _ostype=linux
195206 ;;
196207
@@ -200,6 +211,7 @@ get_architecture() {
200211
201212 * )
202213 err " unrecognized OS type: $_ostype "
214+ exit 1
203215 ;;
204216
205217 esac
@@ -224,18 +236,32 @@ get_architecture() {
224236 RETVAL=" $_arch "
225237}
226238
239+ __print () {
240+ if $_ansi_escapes_are_valid ; then
241+ printf ' \33[1m%s:\33[0m %s\n' " $1 " " $2 " >&2
242+ else
243+ printf ' %s: %s\n' " $1 " " $2 " >&2
244+ fi
245+ }
246+
247+ warn () {
248+ __print ' warn' " $1 " >&2
249+ }
250+
227251say () {
228- printf ' nix-installer: %s\n ' " $1 "
252+ __print ' info ' " $1 " >&2
229253}
230254
255+ # NOTE: you are required to exit yourself
256+ # we don't do it here because of multiline errors
231257err () {
232- say " $1 " >&2
233- exit 1
258+ __print ' error' " $1 " >&2
234259}
235260
236261need_cmd () {
237262 if ! check_cmd " $1 " ; then
238263 err " need '$1 ' (command not found)"
264+ exit 1
239265 fi
240266}
241267
@@ -244,14 +270,20 @@ check_cmd() {
244270}
245271
246272assert_nz () {
247- if [ -z " $1 " ]; then err " assert_nz $2 " ; fi
273+ if [ -z " $1 " ]; then
274+ err " assert_nz $2 "
275+ exit 1
276+ fi
248277}
249278
250279# Run a command that should never fail. If the command fails execution
251280# will immediately terminate with an error showing the failing
252281# command.
253282ensure () {
254- if ! " $@ " ; then err " command failed: $* " ; fi
283+ if ! " $@ " ; then
284+ err " command failed: $* "
285+ exit 1
286+ fi
255287}
256288
257289# This is just for indicating that commands' results are being
@@ -264,13 +296,31 @@ ignore() {
264296# This wraps curl or wget. Try curl first, if not installed,
265297# use wget instead.
266298downloader () {
299+ # zsh does not split words by default, Required for curl retry arguments below.
300+ is_zsh && setopt local_options shwordsplit
301+
267302 local _dld
268303 local _ciphersuites
269304 local _err
270305 local _status
271306 local _retry
272307 if check_cmd curl; then
273- _dld=curl
308+ # Check if we have a broken snap curl
309+ # https://github.com/boukendesho/curl-snap/issues/1
310+ _curl_path=$( command -v curl)
311+ if echo " $_curl_path " | grep " /snap/" > /dev/null 2>&1 ; then
312+ if check_cmd wget; then
313+ _dld=wget
314+ else
315+ err " curl installed with snap cannot be used to install Rust"
316+ err " due to missing permissions. Please uninstall it and"
317+ err " reinstall curl with a different package manager (e.g., apt)."
318+ err " See https://github.com/boukendesho/curl-snap/issues/1"
319+ exit 1
320+ fi
321+ else
322+ _dld=curl
323+ fi
274324 elif check_cmd wget; then
275325 _dld=wget
276326 else
@@ -280,42 +330,38 @@ downloader() {
280330 if [ " $1 " = --check ]; then
281331 need_cmd " $_dld "
282332 elif [ " $_dld " = curl ]; then
283- check_curl_for_retry_and_speed_limit_support
333+ check_curl_for_retry_support
284334 _retry=" $RETVAL "
285335 get_ciphersuites_for_curl
286336 _ciphersuites=" $RETVAL "
287337 if [ -n " $_ciphersuites " ]; then
288- if [ -n " ${NIX_INSTALLER_FORCE_ALLOW_HTTP-} " ]; then
289- # shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
290- _err=$( curl $_retry --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
291- else
292- # shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
293- _err=$( curl $_retry --proto ' =https' --tlsv1.2 --ciphers " $_ciphersuites " --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
294- fi
338+ # shellcheck disable=SC2086
339+ _err=$( curl $_retry --proto ' =https' --tlsv1.2 --ciphers " $_ciphersuites " --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
295340 _status=$?
296341 else
297- echo " Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
342+ warn " Not enforcing strong cipher suites for TLS, this is potentially less secure"
298343 if ! check_help_for " $3 " curl --proto --tlsv1.2; then
299- echo " Warning: Not enforcing TLS v1.2, this is potentially less secure"
300- # shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
344+ warn " Not enforcing TLS v1.2, this is potentially less secure"
345+ # shellcheck disable=SC2086
301346 _err=$( curl $_retry --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
302347 _status=$?
303348 else
304- # shellcheck disable=SC2086 # ignore because $_retry could be a flag (e.g. `--retry 5`)
349+ # shellcheck disable=SC2086
305350 _err=$( curl $_retry --proto ' =https' --tlsv1.2 --silent --show-error --fail --location " $1 " --output " $2 " 2>&1 )
306351 _status=$?
307352 fi
308353 fi
309354 if [ -n " $_err " ]; then
310- echo " $_err " >&2
355+ warn " $_err "
311356 if echo " $_err " | grep -q 404$; then
312357 err " installer for platform '$3 ' not found, this may be unsupported"
358+ exit 1
313359 fi
314360 fi
315361 return $_status
316362 elif [ " $_dld " = wget ]; then
317363 if [ " $( wget -V 2>&1 | head -2| tail -1| cut -f1 -d" " ) " = " BusyBox" ]; then
318- echo " Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure"
364+ warn " using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure"
319365 _err=$( wget " $1 " -O " $2 " 2>&1 )
320366 _status=$?
321367 else
@@ -325,9 +371,9 @@ downloader() {
325371 _err=$( wget --https-only --secure-protocol=TLSv1_2 --ciphers " $_ciphersuites " " $1 " -O " $2 " 2>&1 )
326372 _status=$?
327373 else
328- echo " Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
374+ warn " Not enforcing strong cipher suites for TLS, this is potentially less secure"
329375 if ! check_help_for " $3 " wget --https-only --secure-protocol; then
330- echo " Warning: Not enforcing TLS v1.2, this is potentially less secure"
376+ warn " Not enforcing TLS v1.2, this is potentially less secure"
331377 _err=$( wget " $1 " -O " $2 " 2>&1 )
332378 _status=$?
333379 else
@@ -337,14 +383,16 @@ downloader() {
337383 fi
338384 fi
339385 if [ -n " $_err " ]; then
340- echo " $_err " >&2
386+ warn " $_err "
341387 if echo " $_err " | grep -q ' 404 Not Found$' ; then
342388 err " installer for platform '$3 ' not found, this may be unsupported"
389+ exit 1
343390 fi
344391 fi
345392 return $_status
346393 else
347394 err " Unknown downloader" # should not reach here
395+ exit 1
348396 fi
349397}
350398
@@ -368,32 +416,35 @@ check_help_for() {
368416
369417 * darwin* )
370418 if check_cmd sw_vers; then
371- case $( sw_vers -productVersion) in
372- 10.* )
419+ local _os_version
420+ local _os_major
421+ _os_version=$( sw_vers -productVersion)
422+ _os_major=$( echo " $_os_version " | cut -d. -f1)
423+ case $_os_major in
424+ 10)
373425 # If we're running on macOS, older than 10.13, then we always
374426 # fail to find these options to force fallback
375- if [ " $( sw_vers -productVersion | cut -d. -f2) " -lt 13 ]; then
427+ if [ " $( echo " $_os_version " | cut -d. -f2) " -lt 13 ]; then
376428 # Older than 10.13
377- echo " Warning: Detected macOS platform older than 10.13"
429+ warn " Detected macOS platform older than 10.13"
378430 return 1
379431 fi
380432 ;;
381- 11.* )
382- # We assume Big Sur will be OK for now
383- ;;
384433 * )
385- # Unknown product version, warn and continue
386- echo " Warning: Detected unknown macOS major version: $( sw_vers -productVersion) "
387- echo " Warning TLS capabilities detection may fail"
388- ;;
434+ if ! { [ " $_os_major " -eq " $_os_major " ] 2> /dev/null && [ " $_os_major " -ge 11 ]; }; then
435+ # Unknown product version, warn and continue
436+ warn " Detected unknown macOS major version: $_os_version "
437+ warn " TLS capabilities detection may fail"
438+ fi
439+ ;; # We assume that macOS v11+ will always be okay.
389440 esac
390441 fi
391442 ;;
392443
393444 esac
394445
395446 for _arg in " $@ " ; do
396- if ! " $_cmd " --help $_category | grep -q -- " $_arg " ; then
447+ if ! " $_cmd " --help " $_category " | grep -q -- " $_arg " ; then
397448 return 1
398449 fi
399450 done
@@ -404,20 +455,29 @@ check_help_for() {
404455# Check if curl supports the --retry flag, then pass it to the curl invocation.
405456# Note that --speed-limit and --speed-time were in the very first commit of curl.
406457# So this should be pretty much ubiquitously safe.
407- check_curl_for_retry_and_speed_limit_support () {
408- local _retry_supported=" "
458+ check_curl_for_retry_support () {
459+ local _retry_part=" "
460+ local _continue_part=" "
461+ local _speed_limit_part=" "
409462
410463 # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
411- if check_help_for " notspecified" " curl" " --retry" \
412- && check_help_for " notspecified" " curl" " --speed-limit" \
413- && check_help_for " notspecified" " curl" " --speed-time" ; then
414-
415- # 250000 is approximately 20% of the bandwidth of typical DSL
416- # these limits mean users below these limits will see failures.
417- # I don't believe we have any users like this, and if we do -- please open a ticket.
418- _retry_supported=" --retry 3 --speed-limit 250000 --speed-time 15"
464+ if check_help_for " notspecified" " curl" " --retry" ; then
465+ _retry_part=" --retry 3"
466+
467+ if check_help_for " notspecified" " curl" " --continue-at" ; then
468+ # "-C -" tells curl to automatically find where to resume the download when retrying.
469+ _continue_part=" --continue-at -"
470+ fi
471+
472+ if check_help_for " notspecified" " curl" " --speed-limit" \
473+ && check_help_for " notspecified" " curl" " --speed-time" ; then
474+ # 250000 is approximately 20% of the bandwidth of typical DSL
475+ # these limits mean users below these limits will see failures.
476+ _speed_limit_part=" --speed-limit 250000 --speed-time 15"
477+ fi
419478 fi
420- RETVAL=" $_retry_supported "
479+
480+ RETVAL=" $_retry_part $_continue_part $_speed_limit_part "
421481}
422482
423483
0 commit comments