Skip to content

fix(src/paths.zig): fall back when XDG_RUNTIME_DIR is unusable#44

Merged
kylecarbs merged 1 commit into
mainfrom
fix/xdg-runtime-dir-fallback
Jun 11, 2026
Merged

fix(src/paths.zig): fall back when XDG_RUNTIME_DIR is unusable#44
kylecarbs merged 1 commit into
mainfrom
fix/xdg-runtime-dir-fallback

Conversation

@kylecarbs

Copy link
Copy Markdown
Member

Fixes the error: ReadOnlyFileSystem reported on Hacker News for boo new on macOS Sequoia after a curl-to-bash install.

Problem

socketDir trusted $XDG_RUNTIME_DIR blindly and makePath'd it, parents included. macOS never sets that variable, but dotfiles shared with Linux commonly export XDG_RUNTIME_DIR=/run/user/$UID. /run does not exist on macOS, so makePath walks up and ends at mkdir /run on the sealed read-only system volume, which fails with EROFS. The error escapes main and Zig prints exactly error: ReadOnlyFileSystem.

Fix

The XDG runtime directory is owned by the login session; applications must not create it. socketDir now honors $XDG_RUNTIME_DIR only when the directory already exists and the boo/ subdirectory is creatable inside it, and otherwise falls back to /tmp/boo-<uid>. $BOO_DIR remains an explicit, fail-loud override.

Verification

Reproduced on Linux with a read-only tmpfs standing in for the sealed volume (XDG_RUNTIME_DIR=/mnt/sealed/run/user/501):

  • before: boo new -d testerror: ReadOnlyFileSystem, exit 1
  • after: session starts, socket lands in /tmp/boo-<uid> (0700); a valid XDG_RUNTIME_DIR is still preferred
  • zig build test-all: 131/131 tests pass, including new unit tests for the resolution order and fallback
Investigation notes
  • The only filesystem writes in the foreground boo new path are socketDir (makePath) and the socket bind(2); both can return EROFS, but /tmp/boo-<uid> is writable on a stock Mac, which pointed at the XDG_RUNTIME_DIR branch.
  • Zig 0.15 Dir.makePath retries parent components on FileNotFound, so a missing /run/user/501/boo ends in mkdir /run against the sealed volume.
  • The resolution logic moved into socketDirFrom(alloc, boo_dir, runtime_dir) so unit tests can drive it without mutating the process environment (std.c.setenv is not exposed in Zig 0.15.2).
  • boo help already documents the resolution order as $BOO_DIR, else $XDG_RUNTIME_DIR/boo, else /tmp/boo-<uid>, which remains accurate.
  • tmux behaves the same way (silent /tmp fallback), so no warning is printed when falling back.

This PR was generated by Coder Agents on behalf of @kylecarbs, prompted by a Hacker News bug report.

The XDG runtime directory is created by the login session, never by
applications, but socketDir makePath'd it together with its parents.
With a Linux-style XDG_RUNTIME_DIR=/run/user/<uid> exported from
dotfiles shared with Linux, mkdir /run on the sealed read-only macOS
system volume fails and 'boo new' dies with error.ReadOnlyFileSystem.

Honor XDG_RUNTIME_DIR only when the directory already exists and the
boo subdirectory is creatable inside it; otherwise fall back to
/tmp/boo-<uid>. BOO_DIR stays an explicit, fail-loud override.
@kylecarbs kylecarbs merged commit 6c645d8 into main Jun 11, 2026
5 checks passed
@kylecarbs kylecarbs mentioned this pull request Jun 11, 2026
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.

1 participant