fd63dff65e
Smallest Phase 0 module per CLAUDE.md §4 implementation order.
M.chdir(path) returns (true) or (false, errmsg) — errmsg via
strerror(__errno_location()[0]). Glibc errno is thread-local
behind __errno_location() rather than a plain global, hence the
indirect access.
Verified against PHASE0.md §7 expectation: a libc.chdir() persists
across subsequent io.popen() calls (popen's child inherits the
parent's wd), which is the property executor.lua relies on for `cd`
interception. Smoke:
libc.chdir("/tmp"); io.popen("pwd"):read("*l") --> /tmp
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
34 lines
758 B
Lua
34 lines
758 B
Lua
-- ffi/libc.lua — shared libc bindings: chdir, errno, strerror.
|
|
-- Phase 0: just enough to make `cd` interception work in executor.lua.
|
|
-- See docs/PHASE0.md §7.
|
|
|
|
local ffi = require("ffi")
|
|
|
|
ffi.cdef[[
|
|
int chdir(const char *path);
|
|
int *__errno_location(void);
|
|
char *strerror(int errnum);
|
|
]]
|
|
|
|
local C = ffi.C
|
|
|
|
local M = {}
|
|
|
|
-- Apply chdir per PHASE0.md §7 (intercepts `cd` so wd persists across popen).
|
|
-- Returns: true on success; false, errmsg on failure.
|
|
function M.chdir(path)
|
|
local rc = C.chdir(path)
|
|
if rc == 0 then return true end
|
|
return false, ffi.string(C.strerror(C.__errno_location()[0]))
|
|
end
|
|
|
|
function M.errno()
|
|
return C.__errno_location()[0]
|
|
end
|
|
|
|
function M.strerror(en)
|
|
return ffi.string(C.strerror(en))
|
|
end
|
|
|
|
return M
|