const std = @import("std");const builtin = @import("builtin");const contracts = @import("contracts.zig");const monitor_core = @import("monitor.zig");const terminal_engine = @import("engine.zig");const shell_resolver = @import("shell_resolver.zig");const terminal_store = @import("store.zig");const tmux_session = @import("tmux_session.zig");const host_capabilities = @import("../hosts/host.zig");const session_layout = @import("../session/session_layout.zig");const process_supervisor = @import("../background/process_supervisor.zig");const background_process_provider = @import( "../execution/background_process_provider.zig",);const process_tree = @import("../execution/process_tree.zig");const command_admission = @import("../permissions/command_admission.zig");const sandbox = @import("../permissions/sandbox.zig");const execution_router = @import("../execution/router.zig");const io_mod = @import("../shared/io.zig");const debug_trace = @import("../shared/debug_trace.zig");const types = @import("../shared/types.zig");const workspace_pathing = @import("../workspace/pathing.zig"); const Allocator = std.mem.Allocator; const launcher_mode = "--fx-internal-terminal-launcher";const control_mode = "--fx-internal-terminal-control"; const max_sessions: usize = 16;const max_read_bytes: usize = 64 * 1024;const launcher_config_bytes: usize = contracts.max_command_bytes * 6 + contracts.max_authority_text_bytes * 2 + contracts.max_shell_path_bytes * 2 + 4096;const wait_poll_ns: u64 = 5 * std.time.ns_per_ms;const graceful_close_ms: i64 = 800;const control_poll_ms: i32 = 50;const marker_frame_timeout_ms: i64 = 5_000;const marker_ack_timeout_ms: i64 = tmux_session.marker_acknowledgement_timeout_ms;const command_release_byte: u8 = 2;const control_nonce_len: usize = 32;const marker_frame_len: usize = control_nonce_len + 1;const private_file_permissions = std.Io.File.Permissions.fromMode(0o600);const default_dimensions: contracts.Dimensions = .{ .rows = 24, .columns = 80,};const ioctl_set_controlling_terminal: c_int = switch (builtin.os.tag) { .macos => 0x20007461, .linux => @intCast(std.os.linux.T.IOCSCTTY), else => 0,};const ioctl_set_window_size: c_int = switch (builtin.os.tag) { .macos => @bitCast(@as(u32, 0x80087467)), .linux => @intCast(std.os.linux.T.IOCSWINSZ), else => 0,}; const control_frame_len: usize = 5;const ControlKind = enum(u8) { prepared = 1, shell_ready = 2, command_started = 3, command_exited = 4, command_signal = 5, startup_failed = 6, invalid_term = 7,}; const StartupFailure = enum(u32) { shell_unavailable = 1, profile_failed = 2, control_failed = 3,}; const MarkerKind = enum(u8) { shell_ready = 1, command_started = 2,}; const LauncherConfig = struct { argv: []const []const u8, cwd: []const u8, dimensions: contracts.Dimensions, control_path: []const u8, control_nonce: []const u8, bootstrap_path: []const u8, bootstrap: []const u8, command_path: ?[]const u8, command: ?[]const u8,}; const LauncherWatchdog = struct { child_pid: std.posix.pid_t, done: std.atomic.Value(bool) = .init(false), command_released: std.atomic.Value(bool) = .init(false), host_closed: std.atomic.Value(bool) = .init(false), fn run(self: *LauncherWatchdog) void { var poll_fds = [_]std.posix.pollfd{.{ .fd = std.posix.STDIN_FILENO, .events = std.posix.POLL.IN, .revents = 0, }}; while (!self.done.load(.acquire)) { poll_fds[0].revents = 0; _ = std.posix.poll(&poll_fds, control_poll_ms) catch { self.host_closed.store(true, .release); _ = std.c.kill(-self.child_pid, std.c.SIG.KILL); return; }; if (poll_fds[0].revents == 0) continue; var byte: [1]u8 = undefined; const count = std.posix.read(std.posix.STDIN_FILENO, &byte) catch 0; if (count != 0) { if (byte[0] == command_release_byte) { self.command_released.store(true, .release); } continue; } self.host_closed.store(true, .release); if (!self.done.load(.acquire)) { _ = std.c.kill(-self.child_pid, std.c.SIG.KILL); } return; } }}; const ControlPhase = enum { awaiting_shell, shell_ready, command_started,}; const LauncherControl = struct { server: *std.Io.net.Server, control_path: []const u8, bootstrap_path: []const u8, nonce: []const u8, command_path: ?[]const u8, child_pid: std.posix.pid_t, watchdog: *LauncherWatchdog, done: std.atomic.Value(bool) = .init(false), phase: ControlPhase = .awaiting_shell, failed: bool = false, fn run(self: *LauncherControl) void { self.runInner() catch { self.failed = true; }; } fn runInner(self: *LauncherControl) !void { var poll_fds = [_]std.posix.pollfd{.{ .fd = self.server.socket.handle, .events = std.posix.POLL.IN, .revents = 0, }}; while (!self.done.load(.acquire)) { poll_fds[0].revents = 0; _ = try std.posix.poll(&poll_fds, control_poll_ms); if (poll_fds[0].revents == 0) continue; var stream = self.server.accept(io_mod.getIo()) catch |err| switch (err) { error.ConnectionAborted, error.WouldBlock => continue, else => return err, }; defer stream.close(io_mod.getIo()); var bytes: [marker_frame_len]u8 = undefined; receiveSocketExact( stream.socket, &bytes, marker_frame_timeout_ms, ) catch continue; if (!std.mem.eql( u8, self.nonce, bytes[0..control_nonce_len], )) continue; const kind: MarkerKind = switch (bytes[control_nonce_len]) { 1 => .shell_ready, 2 => .command_started, else => continue, }; if (!try self.acceptMarker(kind)) continue; const finished = self.phase == .command_started or (self.phase == .shell_ready and self.command_path == null); if (finished) { std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), self.control_path, ) catch {}; } try writeAllFd(stream.socket.handle, &.{1}, false); if (finished) { return; } } } fn acceptMarker( self: *LauncherControl, kind: MarkerKind, ) !bool { switch (kind) { .shell_ready => { if (self.phase != .awaiting_shell) return false; setEcho(std.posix.STDOUT_FILENO, true) catch {}; std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), self.bootstrap_path, ) catch {}; try writeControlFd( std.posix.STDERR_FILENO, .shell_ready, @intCast(self.child_pid), ); self.phase = .shell_ready; }, .command_started => { if (self.phase != .shell_ready or self.command_path == null) return false; std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), self.command_path.?, ) catch {}; try writeControlFd( std.posix.STDERR_FILENO, .command_started, @intCast(self.child_pid), ); while (!self.watchdog.command_released.load(.acquire)) { if (self.watchdog.host_closed.load(.acquire)) { return error.LauncherHostClosed; } io_mod.sleep(wait_poll_ns); } self.phase = .command_started; }, } return true; }}; pub const WorkTracker = struct { context: ?*anyopaque, update_fn: *const fn (?*anyopaque, bool) void, monitor_update_fn: ?*const fn (?*anyopaque, bool) void = null, fn update(self: WorkTracker, live: bool) void { self.update_fn(self.context, live); } fn updateMonitor(self: WorkTracker, required: bool) void { const callback = self.monitor_update_fn orelse return; callback(self.context, required); }}; fn isSupported() bool { return isSupportedForOs(builtin.os.tag);} fn isSupportedForOs(os_tag: std.Target.Os.Tag) bool { return host_capabilities.terminalSupportForOs(os_tag).isSupported();} test "native terminal backend selection follows canonical platform support" { const os_tags = [_]std.Target.Os.Tag{ .macos, .linux, .windows, .wasi, .freebsd, .emscripten, }; for (os_tags) |os_tag| { try std.testing.expectEqual( host_capabilities.terminalSupportForOs(os_tag).isSupported(), isSupportedForOs(os_tag), ); } try std.testing.expectEqual(isSupportedForOs(builtin.os.tag), isSupported()); const ExpectedRegistry = if (comptime host_capabilities .terminalSupportForOs(builtin.os.tag) .isSupported()) SupportedRegistry else UnsupportedRegistry; try std.testing.expectEqualStrings( @typeName(ExpectedRegistry), @typeName(Registry), );} pub fn isLauncherModeRaw(raw_args: []const [*:0]const u8) bool { return raw_args.len == 2 and std.mem.eql(u8, std.mem.sliceTo(raw_args[1], 0), launcher_mode);} pub fn isControlModeRaw(raw_args: []const [*:0]const u8) bool { return raw_args.len == 5 and std.mem.eql(u8, std.mem.sliceTo(raw_args[1], 0), control_mode);} pub fn runControlMarker(raw_args: []const [*:0]const u8) !void { if (comptime !isSupported()) return error.TerminalHostUnsupported; if (!isControlModeRaw(raw_args)) return error.InvalidControlMarker; const control_path = std.mem.sliceTo(raw_args[2], 0); const nonce = std.mem.sliceTo(raw_args[3], 0); const event = std.mem.sliceTo(raw_args[4], 0); if (nonce.len != control_nonce_len) return error.InvalidControlMarker; const kind: MarkerKind = if (std.mem.eql(u8, event, "shell-ready")) .shell_ready else if (std.mem.eql(u8, event, "command-started")) .command_started else return error.InvalidControlMarker; const tmux_failure = if (std.mem.startsWith( u8, control_path, "/tmp/fx-tmux-marker-", )) io_mod.getenv("FX_TERMINAL_TEST_TMUX_MARKER_FAILURE") else null; if (tmux_failure) |failure| { if (std.mem.eql(u8, failure, "child-exit")) { return error.InjectedTmuxMarkerChildExit; } if (std.mem.eql(u8, failure, "no-peer")) { while (true) io_mod.sleep(wait_poll_ns); } } var bytes: [marker_frame_len]u8 = @splat(0); @memcpy(bytes[0..control_nonce_len], nonce); bytes[control_nonce_len] = @intFromEnum(kind); const address = try std.Io.net.UnixAddress.init(control_path); var stream = try address.connect(io_mod.getIo()); defer stream.close(io_mod.getIo()); if (tmux_failure) |failure| { if (std.mem.eql(u8, failure, "silent-peer")) { while (true) io_mod.sleep(wait_poll_ns); } if (std.mem.eql(u8, failure, "partial-marker")) { try writeAllFd( stream.socket.handle, bytes[0 .. bytes.len / 2], false, ); while (true) io_mod.sleep(wait_poll_ns); } if (std.mem.eql(u8, failure, "invalid-nonce")) { bytes[0] ^= 1; try writeAllFd(stream.socket.handle, &bytes, false); while (true) io_mod.sleep(wait_poll_ns); } } try writeAllFd(stream.socket.handle, &bytes, false); var ack: [1]u8 = undefined; try receiveSocketExact(stream.socket, &ack, marker_ack_timeout_ms); if (ack[0] != 1) return error.ControlMarkerRejected;} fn writePrivateLauncherFile(path: []const u8, bytes: []const u8) !void { var file = try std.Io.Dir.createFileAbsolute( io_mod.getIo(), path, .{ .exclusive = true, .permissions = private_file_permissions, }, ); errdefer std.Io.Dir.deleteFileAbsolute(io_mod.getIo(), path) catch {}; defer file.close(io_mod.getIo()); try file.writeStreamingAll(io_mod.getIo(), bytes);} pub fn runLauncher(alloc: Allocator) !void { if (comptime !isSupported()) return error.TerminalHostUnsupported; var length_bytes: [4]u8 = undefined; try readExactFd(std.posix.STDIN_FILENO, &length_bytes); const config_len = std.mem.readInt(u32, &length_bytes, .little); if (config_len == 0 or config_len > launcher_config_bytes) { return error.InvalidLauncherConfig; } const config_bytes = try alloc.alloc(u8, config_len); defer alloc.free(config_bytes); try readExactFd(std.posix.STDIN_FILENO, config_bytes); var parsed = try std.json.parseFromSlice( LauncherConfig, alloc, config_bytes, .{ .allocate = .alloc_always }, ); defer parsed.deinit(); if (parsed.value.argv.len == 0) return error.InvalidLauncherConfig; if (!std.fs.path.isAbsolute(parsed.value.cwd) or !std.fs.path.isAbsolute(parsed.value.control_path) or !std.fs.path.isAbsolute(parsed.value.bootstrap_path) or parsed.value.control_nonce.len != control_nonce_len or (parsed.value.command == null) != (parsed.value.command_path == null)) { return error.InvalidLauncherConfig; } if (parsed.value.command_path) |path| { if (!std.fs.path.isAbsolute(path)) return error.InvalidLauncherConfig; } try parsed.value.dimensions.validate(); var bootstrap_created = false; defer if (bootstrap_created) { std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.bootstrap_path, ) catch {}; }; try writePrivateLauncherFile( parsed.value.bootstrap_path, parsed.value.bootstrap, ); bootstrap_created = true; var command_created = false; defer if (command_created) { std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.command_path.?, ) catch {}; }; if (parsed.value.command) |command| { try writePrivateLauncherFile(parsed.value.command_path.?, command); command_created = true; } std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.control_path, ) catch {}; const address = try std.Io.net.UnixAddress.init(parsed.value.control_path); var server = try address.listen(io_mod.getIo(), .{}); defer server.deinit(io_mod.getIo()); defer std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.control_path, ) catch {}; try std.Io.Dir.cwd().setFilePermissions( io_mod.getIo(), parsed.value.control_path, private_file_permissions, .{ .follow_symlinks = false }, ); if (std.c.setsid() < 0) return error.SessionCreationFailed; if (std.c.ioctl( std.posix.STDOUT_FILENO, ioctl_set_controlling_terminal, @as(c_int, 0), ) < 0) return error.ControllingTerminalFailed; try resizeFd(std.posix.STDOUT_FILENO, parsed.value.dimensions); try writeControlFd(std.posix.STDERR_FILENO, .prepared, 0); var release: [1]u8 = undefined; try readExactFd(std.posix.STDIN_FILENO, &release); if (release[0] != 1) return error.InvalidLauncherRelease; const terminal_file = std.Io.File{ .handle = std.posix.STDOUT_FILENO, .flags = .{ .nonblocking = false }, }; var child = std.process.spawn(io_mod.getIo(), .{ .argv = parsed.value.argv, .stdin = .{ .file = terminal_file }, .stdout = .{ .file = terminal_file }, .stderr = .{ .file = terminal_file }, .cwd = .{ .path = parsed.value.cwd }, .pgid = 0, }) catch { try writeControlFd( std.posix.STDERR_FILENO, .startup_failed, @intFromEnum(StartupFailure.shell_unavailable), ); return; }; var child_running = true; errdefer if (child_running) child.kill(io_mod.getIo()); const child_pid = child.id orelse return error.ChildIdentityMissing; if (tcsetpgrp(std.posix.STDOUT_FILENO, child_pid) != 0) { return error.ForegroundProcessGroupFailed; } var watchdog = LauncherWatchdog{ .child_pid = child_pid }; var control = LauncherControl{ .server = &server, .control_path = parsed.value.control_path, .bootstrap_path = parsed.value.bootstrap_path, .nonce = parsed.value.control_nonce,Lines 1–500 of 7225. Load more
const std = @import("std"); const builtin = @import("builtin"); const contracts = @import("contracts.zig"); const monitor_core = @import("monitor.zig"); const terminal_engine = @import("engine.zig"); const shell_resolver = @import("shell_resolver.zig"); const terminal_store = @import("store.zig"); const tmux_session = @import("tmux_session.zig"); const host_capabilities = @import("../hosts/host.zig"); const session_layout = @import("../session/session_layout.zig"); const process_supervisor = @import("../background/process_supervisor.zig"); const background_process_provider = @import( "../execution/background_process_provider.zig", ); const process_tree = @import("../execution/process_tree.zig"); const command_admission = @import("../permissions/command_admission.zig"); const sandbox = @import("../permissions/sandbox.zig"); const execution_router = @import("../execution/router.zig"); const io_mod = @import("../shared/io.zig"); const debug_trace = @import("../shared/debug_trace.zig"); const types = @import("../shared/types.zig"); const workspace_pathing = @import("../workspace/pathing.zig"); const Allocator = std.mem.Allocator; const launcher_mode = "--fx-internal-terminal-launcher"; const control_mode = "--fx-internal-terminal-control"; const max_sessions: usize = 16; const max_read_bytes: usize = 64 * 1024; const launcher_config_bytes: usize = contracts.max_command_bytes * 6 + contracts.max_authority_text_bytes * 2 + contracts.max_shell_path_bytes * 2 + 4096; const wait_poll_ns: u64 = 5 * std.time.ns_per_ms; const graceful_close_ms: i64 = 800; const control_poll_ms: i32 = 50; const marker_frame_timeout_ms: i64 = 5_000; const marker_ack_timeout_ms: i64 = tmux_session.marker_acknowledgement_timeout_ms; const command_release_byte: u8 = 2; const control_nonce_len: usize = 32; const marker_frame_len: usize = control_nonce_len + 1; const private_file_permissions = std.Io.File.Permissions.fromMode(0o600); const default_dimensions: contracts.Dimensions = .{ .rows = 24, .columns = 80, }; const ioctl_set_controlling_terminal: c_int = switch (builtin.os.tag) { .macos => 0x20007461, .linux => @intCast(std.os.linux.T.IOCSCTTY), else => 0, }; const ioctl_set_window_size: c_int = switch (builtin.os.tag) { .macos => @bitCast(@as(u32, 0x80087467)), .linux => @intCast(std.os.linux.T.IOCSWINSZ), else => 0, }; const control_frame_len: usize = 5; const ControlKind = enum(u8) { prepared = 1, shell_ready = 2, command_started = 3, command_exited = 4, command_signal = 5, startup_failed = 6, invalid_term = 7, }; const StartupFailure = enum(u32) { shell_unavailable = 1, profile_failed = 2, control_failed = 3, }; const MarkerKind = enum(u8) { shell_ready = 1, command_started = 2, }; const LauncherConfig = struct { argv: []const []const u8, cwd: []const u8, dimensions: contracts.Dimensions, control_path: []const u8, control_nonce: []const u8, bootstrap_path: []const u8, bootstrap: []const u8, command_path: ?[]const u8, command: ?[]const u8, }; const LauncherWatchdog = struct { child_pid: std.posix.pid_t, done: std.atomic.Value(bool) = .init(false), command_released: std.atomic.Value(bool) = .init(false), host_closed: std.atomic.Value(bool) = .init(false), fn run(self: *LauncherWatchdog) void { var poll_fds = [_]std.posix.pollfd{.{ .fd = std.posix.STDIN_FILENO, .events = std.posix.POLL.IN, .revents = 0, }}; while (!self.done.load(.acquire)) { poll_fds[0].revents = 0; _ = std.posix.poll(&poll_fds, control_poll_ms) catch { self.host_closed.store(true, .release); _ = std.c.kill(-self.child_pid, std.c.SIG.KILL); return; }; if (poll_fds[0].revents == 0) continue; var byte: [1]u8 = undefined; const count = std.posix.read(std.posix.STDIN_FILENO, &byte) catch 0; if (count != 0) { if (byte[0] == command_release_byte) { self.command_released.store(true, .release); } continue; } self.host_closed.store(true, .release); if (!self.done.load(.acquire)) { _ = std.c.kill(-self.child_pid, std.c.SIG.KILL); } return; } } }; const ControlPhase = enum { awaiting_shell, shell_ready, command_started, }; const LauncherControl = struct { server: *std.Io.net.Server, control_path: []const u8, bootstrap_path: []const u8, nonce: []const u8, command_path: ?[]const u8, child_pid: std.posix.pid_t, watchdog: *LauncherWatchdog, done: std.atomic.Value(bool) = .init(false), phase: ControlPhase = .awaiting_shell, failed: bool = false, fn run(self: *LauncherControl) void { self.runInner() catch { self.failed = true; }; } fn runInner(self: *LauncherControl) !void { var poll_fds = [_]std.posix.pollfd{.{ .fd = self.server.socket.handle, .events = std.posix.POLL.IN, .revents = 0, }}; while (!self.done.load(.acquire)) { poll_fds[0].revents = 0; _ = try std.posix.poll(&poll_fds, control_poll_ms); if (poll_fds[0].revents == 0) continue; var stream = self.server.accept(io_mod.getIo()) catch |err| switch (err) { error.ConnectionAborted, error.WouldBlock => continue, else => return err, }; defer stream.close(io_mod.getIo()); var bytes: [marker_frame_len]u8 = undefined; receiveSocketExact( stream.socket, &bytes, marker_frame_timeout_ms, ) catch continue; if (!std.mem.eql( u8, self.nonce, bytes[0..control_nonce_len], )) continue; const kind: MarkerKind = switch (bytes[control_nonce_len]) { 1 => .shell_ready, 2 => .command_started, else => continue, }; if (!try self.acceptMarker(kind)) continue; const finished = self.phase == .command_started or (self.phase == .shell_ready and self.command_path == null); if (finished) { std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), self.control_path, ) catch {}; } try writeAllFd(stream.socket.handle, &.{1}, false); if (finished) { return; } } } fn acceptMarker( self: *LauncherControl, kind: MarkerKind, ) !bool { switch (kind) { .shell_ready => { if (self.phase != .awaiting_shell) return false; setEcho(std.posix.STDOUT_FILENO, true) catch {}; std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), self.bootstrap_path, ) catch {}; try writeControlFd( std.posix.STDERR_FILENO, .shell_ready, @intCast(self.child_pid), ); self.phase = .shell_ready; }, .command_started => { if (self.phase != .shell_ready or self.command_path == null) return false; std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), self.command_path.?, ) catch {}; try writeControlFd( std.posix.STDERR_FILENO, .command_started, @intCast(self.child_pid), ); while (!self.watchdog.command_released.load(.acquire)) { if (self.watchdog.host_closed.load(.acquire)) { return error.LauncherHostClosed; } io_mod.sleep(wait_poll_ns); } self.phase = .command_started; }, } return true; } }; pub const WorkTracker = struct { context: ?*anyopaque, update_fn: *const fn (?*anyopaque, bool) void, monitor_update_fn: ?*const fn (?*anyopaque, bool) void = null, fn update(self: WorkTracker, live: bool) void { self.update_fn(self.context, live); } fn updateMonitor(self: WorkTracker, required: bool) void { const callback = self.monitor_update_fn orelse return; callback(self.context, required); } }; fn isSupported() bool { return isSupportedForOs(builtin.os.tag); } fn isSupportedForOs(os_tag: std.Target.Os.Tag) bool { return host_capabilities.terminalSupportForOs(os_tag).isSupported(); } test "native terminal backend selection follows canonical platform support" { const os_tags = [_]std.Target.Os.Tag{ .macos, .linux, .windows, .wasi, .freebsd, .emscripten, }; for (os_tags) |os_tag| { try std.testing.expectEqual( host_capabilities.terminalSupportForOs(os_tag).isSupported(), isSupportedForOs(os_tag), ); } try std.testing.expectEqual(isSupportedForOs(builtin.os.tag), isSupported()); const ExpectedRegistry = if (comptime host_capabilities .terminalSupportForOs(builtin.os.tag) .isSupported()) SupportedRegistry else UnsupportedRegistry; try std.testing.expectEqualStrings( @typeName(ExpectedRegistry), @typeName(Registry), ); } pub fn isLauncherModeRaw(raw_args: []const [*:0]const u8) bool { return raw_args.len == 2 and std.mem.eql(u8, std.mem.sliceTo(raw_args[1], 0), launcher_mode); } pub fn isControlModeRaw(raw_args: []const [*:0]const u8) bool { return raw_args.len == 5 and std.mem.eql(u8, std.mem.sliceTo(raw_args[1], 0), control_mode); } pub fn runControlMarker(raw_args: []const [*:0]const u8) !void { if (comptime !isSupported()) return error.TerminalHostUnsupported; if (!isControlModeRaw(raw_args)) return error.InvalidControlMarker; const control_path = std.mem.sliceTo(raw_args[2], 0); const nonce = std.mem.sliceTo(raw_args[3], 0); const event = std.mem.sliceTo(raw_args[4], 0); if (nonce.len != control_nonce_len) return error.InvalidControlMarker; const kind: MarkerKind = if (std.mem.eql(u8, event, "shell-ready")) .shell_ready else if (std.mem.eql(u8, event, "command-started")) .command_started else return error.InvalidControlMarker; const tmux_failure = if (std.mem.startsWith( u8, control_path, "/tmp/fx-tmux-marker-", )) io_mod.getenv("FX_TERMINAL_TEST_TMUX_MARKER_FAILURE") else null; if (tmux_failure) |failure| { if (std.mem.eql(u8, failure, "child-exit")) { return error.InjectedTmuxMarkerChildExit; } if (std.mem.eql(u8, failure, "no-peer")) { while (true) io_mod.sleep(wait_poll_ns); } } var bytes: [marker_frame_len]u8 = @splat(0); @memcpy(bytes[0..control_nonce_len], nonce); bytes[control_nonce_len] = @intFromEnum(kind); const address = try std.Io.net.UnixAddress.init(control_path); var stream = try address.connect(io_mod.getIo()); defer stream.close(io_mod.getIo()); if (tmux_failure) |failure| { if (std.mem.eql(u8, failure, "silent-peer")) { while (true) io_mod.sleep(wait_poll_ns); } if (std.mem.eql(u8, failure, "partial-marker")) { try writeAllFd( stream.socket.handle, bytes[0 .. bytes.len / 2], false, ); while (true) io_mod.sleep(wait_poll_ns); } if (std.mem.eql(u8, failure, "invalid-nonce")) { bytes[0] ^= 1; try writeAllFd(stream.socket.handle, &bytes, false); while (true) io_mod.sleep(wait_poll_ns); } } try writeAllFd(stream.socket.handle, &bytes, false); var ack: [1]u8 = undefined; try receiveSocketExact(stream.socket, &ack, marker_ack_timeout_ms); if (ack[0] != 1) return error.ControlMarkerRejected; } fn writePrivateLauncherFile(path: []const u8, bytes: []const u8) !void { var file = try std.Io.Dir.createFileAbsolute( io_mod.getIo(), path, .{ .exclusive = true, .permissions = private_file_permissions, }, ); errdefer std.Io.Dir.deleteFileAbsolute(io_mod.getIo(), path) catch {}; defer file.close(io_mod.getIo()); try file.writeStreamingAll(io_mod.getIo(), bytes); } pub fn runLauncher(alloc: Allocator) !void { if (comptime !isSupported()) return error.TerminalHostUnsupported; var length_bytes: [4]u8 = undefined; try readExactFd(std.posix.STDIN_FILENO, &length_bytes); const config_len = std.mem.readInt(u32, &length_bytes, .little); if (config_len == 0 or config_len > launcher_config_bytes) { return error.InvalidLauncherConfig; } const config_bytes = try alloc.alloc(u8, config_len); defer alloc.free(config_bytes); try readExactFd(std.posix.STDIN_FILENO, config_bytes); var parsed = try std.json.parseFromSlice( LauncherConfig, alloc, config_bytes, .{ .allocate = .alloc_always }, ); defer parsed.deinit(); if (parsed.value.argv.len == 0) return error.InvalidLauncherConfig; if (!std.fs.path.isAbsolute(parsed.value.cwd) or !std.fs.path.isAbsolute(parsed.value.control_path) or !std.fs.path.isAbsolute(parsed.value.bootstrap_path) or parsed.value.control_nonce.len != control_nonce_len or (parsed.value.command == null) != (parsed.value.command_path == null)) { return error.InvalidLauncherConfig; } if (parsed.value.command_path) |path| { if (!std.fs.path.isAbsolute(path)) return error.InvalidLauncherConfig; } try parsed.value.dimensions.validate(); var bootstrap_created = false; defer if (bootstrap_created) { std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.bootstrap_path, ) catch {}; }; try writePrivateLauncherFile( parsed.value.bootstrap_path, parsed.value.bootstrap, ); bootstrap_created = true; var command_created = false; defer if (command_created) { std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.command_path.?, ) catch {}; }; if (parsed.value.command) |command| { try writePrivateLauncherFile(parsed.value.command_path.?, command); command_created = true; } std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.control_path, ) catch {}; const address = try std.Io.net.UnixAddress.init(parsed.value.control_path); var server = try address.listen(io_mod.getIo(), .{}); defer server.deinit(io_mod.getIo()); defer std.Io.Dir.deleteFileAbsolute( io_mod.getIo(), parsed.value.control_path, ) catch {}; try std.Io.Dir.cwd().setFilePermissions( io_mod.getIo(), parsed.value.control_path, private_file_permissions, .{ .follow_symlinks = false }, ); if (std.c.setsid() < 0) return error.SessionCreationFailed; if (std.c.ioctl( std.posix.STDOUT_FILENO, ioctl_set_controlling_terminal, @as(c_int, 0), ) < 0) return error.ControllingTerminalFailed; try resizeFd(std.posix.STDOUT_FILENO, parsed.value.dimensions); try writeControlFd(std.posix.STDERR_FILENO, .prepared, 0); var release: [1]u8 = undefined; try readExactFd(std.posix.STDIN_FILENO, &release); if (release[0] != 1) return error.InvalidLauncherRelease; const terminal_file = std.Io.File{ .handle = std.posix.STDOUT_FILENO, .flags = .{ .nonblocking = false }, }; var child = std.process.spawn(io_mod.getIo(), .{ .argv = parsed.value.argv, .stdin = .{ .file = terminal_file }, .stdout = .{ .file = terminal_file }, .stderr = .{ .file = terminal_file }, .cwd = .{ .path = parsed.value.cwd }, .pgid = 0, }) catch { try writeControlFd( std.posix.STDERR_FILENO, .startup_failed, @intFromEnum(StartupFailure.shell_unavailable), ); return; }; var child_running = true; errdefer if (child_running) child.kill(io_mod.getIo()); const child_pid = child.id orelse return error.ChildIdentityMissing; if (tcsetpgrp(std.posix.STDOUT_FILENO, child_pid) != 0) { return error.ForegroundProcessGroupFailed; } var watchdog = LauncherWatchdog{ .child_pid = child_pid }; var control = LauncherControl{ .server = &server, .control_path = parsed.value.control_path, .bootstrap_path = parsed.value.bootstrap_path, .nonce = parsed.value.control_nonce,