diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 15:36:47 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | b9eefda75ab9a63fc510de781d02b92fc04ad31d (patch) | |
| tree | 10ad6accba3a767a37fcd334d6316a2fc3f53442 /src/9p_io.zig | |
| parent | 12c257e624d3f1f80ca3df041b54026ff772d638 (diff) | |
| parent | 31b7bcbae734cd1d0a432ff5acaf9c65bcd33897 (diff) | |
| download | pardes-b9eefda75ab9a63fc510de781d02b92fc04ad31d.tar.gz pardes-b9eefda75ab9a63fc510de781d02b92fc04ad31d.zip | |
Release Pardes 0.8
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/9p_io.zig')
| -rw-r--r-- | src/9p_io.zig | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/9p_io.zig b/src/9p_io.zig index 0eaa2d7e..e475416e 100644 --- a/src/9p_io.zig +++ b/src/9p_io.zig @@ -874,7 +874,29 @@ pub fn listen(io: std.Io, gpa: std.mem.Allocator, core: *pardes.Pardes, named: [ .greet_timeout_ms = Listener.greet_deadline_ms, }); const p = socketPath(&l.path_buf, dir, entry_name).?; - _ = l.runner.listen(.{ .unix = p }, max_conns) catch |err| retry: { + // Listened on under a name of its own, then renamed into place: a client + // that waits for the socket to appear finds it listening already. Bound + // at its own name, it was there a moment before listen(2), and a connect + // then was refused. (No room for the longer name: bound in place.) + var tmp_buf: [sun_path_len]u8 = undefined; + if (std.fmt.bufPrintSentinel(&tmp_buf, "{s}.{d}", .{ p, libc.getpid() }, 0) catch null) |tmp| { + const existing = @import("fs.zig").statPath(io, p, .{ .follow_symlinks = false }) catch null; + if (existing != null and (existing.?.kind != .unix_domain_socket or alive(p))) { + log.warn("something is already listening on {s}", .{p}); + l.deinit(gpa); + return null; + } + _ = libc.unlink(tmp); + _ = l.runner.listen(.{ .unix = tmp }, max_conns) catch { + l.deinit(gpa); + return null; + }; + if (libc.chmod(tmp, 0o600) != 0 or libc.rename(tmp, p) != 0) { + _ = libc.unlink(tmp); + l.deinit(gpa); + return null; + } + } else _ = l.runner.listen(.{ .unix = p }, max_conns) catch |err| retry: { const existing = @import("fs.zig").statPath(io, p, .{ .follow_symlinks = false }) catch null; if (err != error.AddressInUse or existing == null or existing.?.kind != .unix_domain_socket or alive(p)) { log.warn("something is already listening on {s}", .{p}); @@ -1338,6 +1360,11 @@ test "a listening editor posts itself into the 9P registry and unposts on stop" // The socket stays exactly where pardes has always bound it: // adopting the registry moves nothing, it only advertises. try testing.expect(statNoFollow(sock) != null); + // It appeared already listening, renamed into place from a name of + // its own, which is gone. + try testing.expect(alive(sock)); + var tmp_buf: [sun_path_len:0]u8 = undefined; + try testing.expect(statNoFollow(try std.fmt.bufPrintSentinel(&tmp_buf, "{s}.{d}", .{ sock, libc.getpid() }, 0)) == null); // And the registry holds a symlink to it one directory down, so // several editors group under /mnt/9p/pardes/ instead of // crowding the registry root — the layout zmx posts its |
