crossterm-rs / crossterm

Cross platform terminal library rust
MIT License
3.3k stars 280 forks source link

Regression in 0.24.0 with Docker distroless causing "No such file or directory" error #741

Open fujiapple852 opened 1 year ago

fujiapple852 commented 1 year ago

Describe the bug This took some tracking down!

Using crossterm 0.24 (or 0.25) in Docker with the Google distroless image (gcr.io/distroless/cc) results in a No such file or directory error.

This error does not occur with crossterm 0.23.2. The specific commit which introduced the regression is https://github.com/crossterm-rs/crossterm/commit/f523c110a6c65b5428eeb3f582b2bfe527bfc28f (https://github.com/crossterm-rs/crossterm/pull/680)

Note that this error does not occur when using other base images such as ubuntu, it is specific to the combination of the above distroless image and the changes in the above commit.

To Reproduce Steps to reproduce the behavior:

  1. Clone the following repo: https://github.com/fdehau/tui-rs
  2. Create the following Dockerfile:
    
    FROM rust:1.66.0 as build-env
    WORKDIR /app
    COPY . /app
    RUN cargo build --release --example demo

FROM gcr.io/distroless/cc COPY --from=build-env /app/target/release/examples/demo / ENTRYPOINT [ "./demo" ]

3. Build the Docker image:

docker build . -t tui:latest --no-cache

4. Run the container:

docker run -it tui:latest

5. It will fail with the following error (tested on MacOS):

Error: Custom { kind: Other, error: "No such file or directory (os error 2)" }



The issue can be fixed by reverting  https://github.com/crossterm-rs/crossterm/commit/f523c110a6c65b5428eeb3f582b2bfe527bfc28f on top of the current `master`.

**OS**
MacOS

**Terminal/Console**
 iterm2
fujiapple852 commented 1 year ago

Examining the commit in question the difference appears to be in the handing when the ioctl call reports a zero size:

I think the fix should be: if the ioctl call reports a zero size then fallback to tput_size() but if that fails then fallback to returning Ok(0, 0). If you agree I'll raise a PR with this simple fix.

cc @Siphalor

TimonPost commented 1 year ago

But the error is correct, why would we return Ok if it is an error? Perhaps tui should fall back if this function returns an error?

fujiapple852 commented 1 year ago

@TimonPost i suppose it depends on whether you wish crossterm to work in environments where tput is not available, such as distroless containers and also alpine.

Ideally it would (and did until 0.24) but if you don’t want to support that then it would be worth making the dependency explicit and updating the error message to make the context of the error clear (it took quite a bit of effort to trace the general No such file or directory back to this specific issue).

mgunyho commented 8 months ago

This came up also for me in a similar context in https://github.com/mgunyho/tere/issues/93, where my app (still using v0.24) is run in a chroot or clean nix environment as part of an integration test, so the ioctl returns zero size and tput_size() gives the misleading file not found error because tput is not available in those environments.

Note however that #790 removed the zero-size check here, perhaps by mistake? There is also #422, but seems like tput is still used as of 0.27.