0

I'm trying to wrap an executable that takes an input and output file paths as arguments, such that it will be possible to provide the input and output as stdin and stdout.

I've written a short script in Go that attempts to do this, but for some reason which eludes me, it hangs forever.

See https://goplay.space/#le6Hexg1ZiJ.

I can add more details as required, but to start, I'd rather not pollute the question with possibly less relevant information.

EDIT: As requested, I'm adding the code here.

package main

import (
    "bytes"
    "io"
    "log"
    "os"
    "strings"
    "syscall"

    "golang.org/x/sync/errgroup"
)

/*
    Expected behavior:

    # Terminal 1
    $ go run main.go

    # Terminal 2
    $ cat inPipe > outPipe

    The go program is writing to inPipe and reading from outPipe

    Actual behavior: The program stalls
*/

func main() {
    eg := &errgroup.Group{}

    inPipe := "inPipe"
    outPipe := "outPipe"

    if err := syscall.Mkfifo(inPipe, 0644); err != nil {
        log.Fatal(err)
    }
    defer os.Remove(inPipe)

    if err := syscall.Mkfifo(outPipe, 0644); err != nil {
        log.Fatal(err)
    }
    defer os.Remove(outPipe)

    fIn, err := os.OpenFile(inPipe, os.O_WRONLY, os.ModeNamedPipe)
    if err != nil {
        log.Fatal(err)
    }
    defer fIn.Close()

    eg.Go(func() error {
        _, err := io.Copy(fIn, strings.NewReader("123"))
        return err
    })

    fOut, err := os.OpenFile(outPipe, os.O_RDONLY, os.ModeNamedPipe)
    if err != nil {
        log.Fatal(err)
    }
    defer fOut.Close()

    buf := &bytes.Buffer{}

    eg.Go(func() error {
        _, err := io.Copy(buf, fOut)
        return err
    })

    if err := eg.Wait(); err != nil {
        log.Fatal(err)
    }

    if _, err := io.Copy(os.Stdout, buf); err != nil {
        log.Fatal(err)
    }
}
rikonor
  • 409
  • 1
  • 4
  • 15
  • 1
    Please add the code to the question by editing it. – Markus W Mahlberg Feb 07 '18 at 07:55
  • You need to open the pipes as non-blocking, or your `Open` call just sits there waiting for the other end to show up. See this [pipes 101 with Go](http://www.albertoleal.me/posts/golang-pipes.html) for more details. I would recommend you get one pipe right before trying both. – Marc Feb 07 '18 at 09:12
  • @marc I actually did try adding `syscall.O_NONBLOCK` to the file mode but it causes an error: `device not configured`. I did go through getting each pipe working on it's own first which culminated in the code I posted above. The weird thing is that if I run the code, then do this in two different terminals: `$ cat inPipe` and `$ echo 123 > outPipe`, then the code progresses as expected, but if I try to do it in one command, e.g `$ cat inPipe > outPipe` then Open still hangs. Not sure why. – rikonor Feb 07 '18 at 14:45

0 Answers0