github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/iodaemon/link/link.go (about) 1 package link 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "os" 8 "sync" 9 "syscall" 10 ) 11 12 type Link struct { 13 *Writer 14 15 exitStatus io.Reader 16 streaming *sync.WaitGroup 17 } 18 19 func Create(socketPath string, stdout io.Writer, stderr io.Writer) (*Link, error) { 20 conn, err := net.Dial("unix", socketPath) 21 if err != nil { 22 return nil, fmt.Errorf("failed to connect to i/o daemon: %s", err) 23 } 24 25 var b [2048]byte 26 var oob [2048]byte 27 28 n, oobn, _, _, err := conn.(*net.UnixConn).ReadMsgUnix(b[:], oob[:]) 29 if err != nil { 30 return nil, fmt.Errorf("failed to read unix msg: %s (read: %d, %d)", err, n, oobn) 31 } 32 33 scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) 34 if err != nil { 35 return nil, fmt.Errorf("failed to parse socket control message: %s", err) 36 } 37 38 if len(scms) < 1 { 39 return nil, fmt.Errorf("no socket control messages sent") 40 } 41 42 scm := scms[0] 43 44 fds, err := syscall.ParseUnixRights(&scm) 45 if err != nil { 46 return nil, fmt.Errorf("failed to parse unix rights: %s", err) 47 } 48 49 if len(fds) != 3 { 50 return nil, fmt.Errorf("invalid number of fds; need 3, got %d", len(fds)) 51 } 52 53 lstdout := os.NewFile(uintptr(fds[0]), "stdout") 54 lstderr := os.NewFile(uintptr(fds[1]), "stderr") 55 lstatus := os.NewFile(uintptr(fds[2]), "status") 56 57 streaming := &sync.WaitGroup{} 58 59 linkWriter := NewWriter(conn) 60 61 streaming.Add(1) 62 go func() { 63 io.Copy(stdout, lstdout) 64 lstdout.Close() 65 streaming.Done() 66 }() 67 68 streaming.Add(1) 69 go func() { 70 io.Copy(stderr, lstderr) 71 lstderr.Close() 72 streaming.Done() 73 }() 74 75 return &Link{ 76 Writer: linkWriter, 77 78 exitStatus: lstatus, 79 streaming: streaming, 80 }, nil 81 } 82 83 func (link *Link) Wait() (int, error) { 84 link.streaming.Wait() 85 86 var exitStatus int 87 _, err := fmt.Fscanf(link.exitStatus, "%d\n", &exitStatus) 88 if err != nil { 89 return -1, fmt.Errorf("could not determine exit status: %s", err) 90 } 91 92 return exitStatus, nil 93 }