ref: 804ca7d4abe311fb94e02c8e1cd56aad8865a959
dir: /lib/std/spork.myr/
use "die" use "errno" use "execvp" use "fmt" use "result" use "syswrap" use "wait" pkg std = const run : (cmd : byte[:][:] -> waitstatus) const spork : (cmd : byte[:][:] -> result((pid, fd, fd), errno)) const espork : (cmd : byte[:][:] -> result((pid, fd, fd, fd), errno)) const filterfd : (fd : fd, cmd : byte[:][:] -> result(pid, errno)) ;; const run = {cmd var pid pid = fork() /* error */ if pid < 0 -> `Waiterror elif pid == 0 execvp(cmd[0], cmd) die("failed exec\n") else -> wait(pid) ;; } const spork = {cmd var infds : fd[2], outfds : fd[2] var err /* open up pipes */ err = pipe(&infds) if err != Enone -> `Err err ;; err = pipe(&outfds) if err != Enone -> `Err err ;; match sporkfd(cmd, infds, outfds, [-1, 2]) | `Ok pid: /* close unused fd ends */ close(infds[0]); close(outfds[1]); -> `Ok (pid, infds[1], outfds[0]) | `Err m: -> `Err m ;; } const espork = {cmd var infds : fd[2], outfds : fd[2], errfds : fd[2] var err /* open up pipes */ err = pipe(&infds) if err != Enone -> `Err err ;; err = pipe(&outfds) if err != Enone -> `Err err ;; err = pipe(&errfds) if err != Enone -> `Err err ;; match sporkfd(cmd, infds, outfds, errfds) | `Ok pid: /* close unused fd ends */ close(infds[0]); close(outfds[1]); close(errfds[1]); -> `Ok (pid, infds[1], outfds[0], errfds[0]) | `Err m: -> `Err m ;; } const filterfd = {fd, cmd var outfds : fd[2] var err err = pipe(&outfds) if err != Enone -> `Err err ;; match sporkfd(cmd, [fd, -1], outfds, [-1, 2]) | `Ok pid: dup2(outfds[0], fd) close(outfds[0]); close(outfds[1]); -> `Ok pid | `Err e: -> `Err e ;; } const sporkfd = {cmd, infds, outfds, errfds var pid pid = fork() /* error */ if pid < 0 /* we don't want to leak the pipe fds on error */ close(infds[0]); close(infds[1]); close(outfds[0]); close(outfds[1]); close(errfds[0]); close(errfds[1]); -> `Err (pid : errno) /* child */ elif pid == 0 /* stdin/stdout for our communication. */ match dup2(infds[0], 0) | `Ok _: /* nothing */ | `Err e: -> `Err e ;; match dup2(outfds[1], 1) | `Ok _: /* nothing */ | `Err e: -> `Err e ;; match dup2(errfds[1], 2) | `Ok _: /* nothing */ | `Err e: -> `Err e ;; /* close the fds we duped */ if infds[0] != 0 close(infds[0]) ;; if outfds[1] != 1 close(outfds[1]) ;; if errfds[1] != 2 close(errfds[1]) ;; /* close the unused ends */ close(infds[1]) close(outfds[0]) close(errfds[0]) execvp(cmd[0], cmd) /* if fork succeeds, we never return */ die("exec failed") /* parent */ else -> `Ok pid ;; }