I am trying to build a shell, but I am struggling with redirecting stdin to children processes, like so:
// I am trying to emulate
//
// echo <args> | cat
const std = @import("std");
const Io = std.Io;
const linux = std.os.linux;
// sample built-in echo function
fn echo(argv: []const []const u8, io: Io, stdout: Io.File) !void {
var buf: [256]u8 = undefined;
var bw = stdout.writer(io, &buf);
var writer = &bw.interface;
for (argv[1..argv.len]) |arg| {
try writer.writeAll(arg);
try writer.writeAll(" ");
}
try writer.writeAll("\n");
try writer.flush();
}
pub fn main(init: std.process.Init) !void {
var cat_proc = try std.process.spawn(init.io, .{
.argv = &.{"cat"},
.stdin = .pipe,
});
try echo(&.{"echo", "hello"}, init.io, cat_proc.stdin.?);
// without this line, cat hangs,
// because it is expecting more input
// (i.e. read(2) has not read EOF yet)
cat_proc.stdin.?.close(init.io);
const term = try cat_proc.wait(init.io);
switch (term) {
.exited => |code| std.debug.print("cat exited {}\n", .{code}),
.signal => |sig| std.debug.print("cat recived signal {}\n", .{sig}),
.stopped => std.debug.print("cat stopped!\n", .{}),
.unknown => std.debug.print("oops\n", .{}),
}
}
Currently, wait also tries to close cat_proc.stdin, and since I have already closed it, it invokes illegal behavior.
My question is, how do I signal to the child process that it has reached EOF without prematurely closing it’s stdin?