Skip to content

Fix ETXTBSY on Linux during update (#8468)#8469

Open
umago wants to merge 1 commit intoaaif-goose:mainfrom
umago:ISSUE-8468
Open

Fix ETXTBSY on Linux during update (#8468)#8469
umago wants to merge 1 commit intoaaif-goose:mainfrom
umago:ISSUE-8468

Conversation

@umago
Copy link
Copy Markdown

@umago umago commented Apr 10, 2026

Summary

On Linux, the kernel enforces ETXTBSY ("Text file busy") and refuses to open a file for writting if that file is being executed.

The original code prior to this change used "fs::copy(...)" which opens the destination file for writting and this was being blocked by the ETXTBSY error.

This patch fixes the issue by copying the new binary to a temp file in the same directory as the current executable and then uses "fs::rename" to atomically swap the directory entry (it only updates the directory mapping it doesn't open the file's content).

This basically mimics what is already implemented for Windows in the update.rs module but adapted for Unix semantics.

Fixes #8468

Testing

Unit test (test_replace_binary_unix_no_leftover_tmp) and manual test.

Related Issues

Relates to #8468
Discussion: LINK (if any)

Screenshots/Demos (for UX changes)

Before:

$ goose update
Downloading goose-x86_64-unknown-linux-gnu.tar.bz2 from stable release...
Downloaded 72451366 bytes.
Archive SHA-256: 47f5cbc3b55a36fa55b85b7166c606758dd2595137b1c5d246ddf32556a99087
Verifying SLSA provenance via Sigstore...
Sigstore provenance verification passed.
Error: Failed to replace current binary

Caused by:
    0: Failed to copy new binary to /home/lmartins/.local/bin/goose
    1: Text file busy (os error 26)

After:

$ ./target/debug/goose update
Downloading goose-x86_64-unknown-linux-gnu.tar.bz2 from stable release...
Downloaded 72451366 bytes.
Archive SHA-256: 47f5cbc3b55a36fa55b85b7166c606758dd2595137b1c5d246ddf32556a99087
Verifying SLSA provenance via Sigstore...
Sigstore provenance verification passed.
goose updated successfully (verified with Sigstore SLSA provenance).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 058b88e3eb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

On Linux, the kernel enforces ETXTBSY ("Text file busy") and refuses to
open a file for writting if that file is being executed.

The original code prior to this change used "fs::copy(...)" which opens
the destination file for writting and this was being blocked by the
ETXTBSY error.

This patch fixes the issue by copying the new binary to a temp file in
the same directory as the current executable and then uses "fs::rename"
to atomically swap the directory entry (it only updates the directory
mapping it doesn't open the file's content).

This basically mimics what is already implemented for Windows in the
update.rs module but adapted for Unix semantics.

Fixes aaif-goose#8468

Signed-off-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf9f911c18

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +474 to +477
let tmp_path = dest_dir.join(format!("goose-update-{}", std::process::id()));

fs::copy(new_binary, &tmp_path)
.with_context(|| format!("Failed to write update to {}", tmp_path.display()))?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Create temp update file with collision-safe semantics

Fresh evidence in this revision: tmp_path is now derived from goose-update-{pid}, which is still deterministic. If a file (or symlink) with that name already exists in the install directory—e.g., from PID reuse, a stale artifact, or a shared writable bin dir—fs::copy will overwrite it and the subsequent rename will remove that entry, causing unintended data loss and potentially writing through a symlink target. Use an atomic create_new/randomized temp filename in dest_dir to guarantee uniqueness before copying.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not deterministic across runs, since different processes ID will be assigned to it. The goose update command is a one-off so, I think it's grand using goose-update-<pid>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Goose CLI fails to update on linux (ETXTBSY)

1 participant