Closing Child Process stdin

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?

If you set stdin to null after closing it then wait() wouldn’t crash.

1 Like

Of course! I’m not sure why I couldn’t see that. Thank you!

1 Like