Skip to content

install.sh: fresh install aborts on missing .b2 checksum (404) and hangs in infinite loop on re-run without a TTY #301

Description

@dmytri

Summary

The official install script (curl -L https://sh.distant.dev | sh) is broken in two independent ways on a standard Linux host (Ubuntu 24.04, /bin/sh = dash):

  1. Fresh install aborts silently because the script tries a BLAKE2 (.b2) checksum that releases don't ship, and the 404 handler hard-exits before the SHA256 fallback can run.
  2. Re-running the script hangs in an infinite loop (eventually OOM/spew) when stdin is a pipe and there's no /dev/tty.

Tested with the script served from https://sh.distant.dev (sha256 of my copy aborts at the same place), distant release v0.20.0.


Bug 1: .b2 checksum 404 aborts install (SHA256 fallback unreachable)

verify_checksum() tries BLAKE2 first when b2sum is present:

if check_cmd b2sum; then
    local _checksum_url="${_url}.b2"
    ...
    if downloader "$_checksum_url" "$_tmpsum" "$_arch" 2>/dev/null; then

But the v0.20.0 release assets only contain *.sha256sum files — there is no .b2 (and no .sha256):

distant-x86_64-unknown-linux-gnu            -> 200
distant-x86_64-unknown-linux-gnu.b2         -> 404
distant-x86_64-unknown-linux-gnu.sha256     -> 404
distant-x86_64-unknown-linux-gnu.sha256sum  -> 200

The intent is for the .b2 download to fail gracefully and fall through to SHA256. But downloader() turns any 404 into a fatal err (which calls exit 1):

if [ -n "$_err" ]; then
    echo "$_err" >&2
    if echo "$_err" | grep -q 404$; then
        err "binary for platform '$3' not found, this may be unsupported"
    fi
fi

So when b2sum is installed (it is, by default, on Ubuntu 24.04 via coreutils), the .b2 fetch 404s, downloader calls err/exit, and the script dies before the SHA256 path. The 2>/dev/null in verify_checksum even hides the message, so the user just sees:

Initializing...
Downloading https://github.com/chipsenkbeil/distant/releases/latest/download/distant-x86_64-unknown-linux-gnu to /home/me/.local/bin/distant

…and then nothing — no binary installed, exit code 1.

Reproduce

$ b2sum --version    # present on stock Ubuntu 24.04
$ curl -L https://sh.distant.dev | sh
Initializing...
Downloading .../distant-x86_64-unknown-linux-gnu to ~/.local/bin/distant
$ echo $?
1
$ ls ~/.local/bin/distant
ls: cannot access ... : No such file or directory

sh -x trace ends at:

+ downloader https://.../distant-x86_64-unknown-linux-gnu.b2 /tmp/tmp.XXXX x86_64-unknown-linux-gnu
(script exits here)

Suggested fix

Either ship .b2 checksums in releases, or make the checksum-download path tolerant of a missing checksum file. The cleanest fix is to not treat a checksum-URL 404 as fatal — e.g. have downloader return non-zero on 404 instead of exiting, or add a "soft" download mode for checksum probes. Also worth probing .sha256sum (the name actually published) in the SHA256 fallback — currently it tries .sha256 then .sha256sum, but it never gets there.


Bug 2: Infinite loop on re-run via pipe (no /dev/tty)

When distant is already installed and --on-conflict is the default (ask):

*)
    local _answer
    while [ ! "${_answer:-}" = "y" ] && [ ! "${_answer:-}" = "n" ]; do
        _answer=$(prompt "Distant is already installed. Overwrite it? (y/n)" "")
    done

prompt() reads from /dev/tty when stdin is not a TTY:

if [ ! -t 0 ]; then
    read -r _value < /dev/tty
else
    read -r _value
fi

In a piped install (curl ... | sh) there is no controlling terminal, so /dev/tty can't be opened. Under dash this produces:

Distant is already installed. Overwrite it? (y/n): install.sh: 561: cannot open /dev/tty: No such device or address
install.sh: 566: _value: parameter not set

read fails, _value is never set, the while condition is never satisfied, and the loop spins forever printing the prompt (I had to kill it after it produced ~55MB / 724k lines of output).

Note there's already logic at the top that forces fail when QUIET=yes, but a normal piped, non-quiet install still reaches this loop.

Reproduce

# with distant already installed at ~/.local/bin/distant
$ curl -L https://sh.distant.dev | sh
Distant is already installed. Overwrite it? (y/n): install.sh: ... cannot open /dev/tty ...
# spins forever

Suggested fix

Detect that no TTY is available and bail out with a clear message (or honor --on-conflict fail) instead of looping. At minimum, break the loop if read fails / /dev/tty can't be opened. The README example curl -L https://sh.distant.dev | sh -s -- --on-conflict overwrite works around it, but the documented default one-liner should not hang.


Environment

  • OS: Ubuntu 24.04.4 LTS, x86_64
  • /bin/sh -> dash
  • b2sum present (coreutils), sha256sum present
  • distant release: v0.20.0 (latest)

Workaround

Manual download works fine:

curl -fL https://github.com/chipsenkbeil/distant/releases/latest/download/distant-x86_64-unknown-linux-gnu \
  -o ~/.local/bin/distant && chmod +x ~/.local/bin/distant

distant --version -> distant 0.20.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions