Skip to content

Re-running sysknife-setup while the daemon runs fails with ETXTBSY and can leave mismatched binaries #563

Open

Description

@vladimirrott

Re-running sysknife-setup while the user daemon is running fails with ETXTBSY: text file busy and aborts the wizard, possibly after the CLI binary was already replaced.

What happens

packages/setup/install-binary.js:495 writes the binary with fsp.writeFile(destPath, data, { mode: 0o755 }), which opens the existing file with O_TRUNC. Linux refuses that for a file being executed. The catch at 497-500 handles EACCES and EPERM only and rethrows the rest, and the caller at 754-762 prints Install failed: ... and exits 1.

The installed user unit is enabled with Restart=on-failure, so after any successful install the daemon is normally running from ~/.local/bin/sysknife-daemon. Re-running the wizard is the documented upgrade path, so this hits every upgrade.

The primitive reproduces in two lines:

cp /bin/sleep ./fakebin && ./fakebin 5 &
node -e "require('fs').promises.writeFile('./fakebin', Buffer.from('x'), {mode: 0o755}).catch(e => console.log(e.code))"
# ETXTBSY

Fix

Write to destPath + '.new' with mode 0755, then fsp.rename() it over destPath. Rename is atomic and allowed over a running executable: the running process keeps the old inode. Then restart the user unit if it was active, or tell the user to.

Write both binaries to .new first and rename only when both succeeded, so a failure never leaves a CLI and daemon from different releases.

Done when

A test starts a process from a fake binary, re-installs over it through install-binary.js, and asserts the install succeeds and the file on disk is the new content.

Getting started

CONTRIBUTING.md has the build and test commands. No CLA and no copyright waiver. The project is MIT; sign off each commit with git commit -s (the required dco check enforces it since #732). Comment here before you start, so nobody doubles up.

Activity

  1. added
    bugSomething isn't working
    easyDifficulty: self-contained, no deep context needed
    on Oct 1, 2026
  2. vladimirrott commented on Oct 1, 2026

    @vladimirrott
    MemberAuthor

    @Jah-yee This one is a contained Node fix in the setup wizard (write to a temp file, then rename), with a two-line reproduction in the issue. I'm holding it for you if you want it.

  3. added
    claimedSomeone has said in the thread that they are working on this
    on Oct 1, 2026
  4. vladimirrott commented on Oct 13, 2026

    @vladimirrott
    MemberAuthor

    @Jah-yee I held this for you on 1 October and I'm putting it back in the pool so someone else can pick it up. If you want it later, say so here and it's yours again.

  5. added
    twir-listedListed in a This Week in Rust CfP. Do not offer to anyone until that issue publishes.
    and removed
    claimedSomeone has said in the thread that they are working on this
    twir-listedListed in a This Week in Rust CfP. Do not offer to anyone until that issue publishes.
    on Oct 13, 2026
  6. vladimirrott commented on Oct 26, 2026

    @vladimirrott
    MemberAuthor

    @dannyward630, I'm holding this one for you. It's the setup wizard on a re-run: replacing the binary while the daemon runs fails with ETXTBSY.

    Say "mine" here when you want it and I'll assign it; nobody else gets offered it meanwhile. Passing on it is fine too.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingeasyDifficulty: self-contained, no deep context needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions