Merge pull request #515 from crosbymichael/readall

Do not use stream encoders for pipe communication
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 19b8f3a..4015c95 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -21,6 +21,7 @@
 	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/criurpc"
+	"github.com/opencontainers/runc/libcontainer/utils"
 	"github.com/vishvananda/netlink/nl"
 )
 
@@ -964,7 +965,7 @@
 		return err
 	}
 	defer f.Close()
-	return json.NewEncoder(f).Encode(s)
+	return utils.WriteJSON(f, s)
 }
 
 func (c *linuxContainer) deleteState() error {
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index 30ea7a7..0e4e9df 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -18,6 +18,7 @@
 	"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/configs/validate"
+	"github.com/opencontainers/runc/libcontainer/utils"
 )
 
 const (
@@ -235,15 +236,15 @@
 		if err != nil {
 			if _, ok := i.(*linuxStandardInit); ok {
 				//  Synchronisation only necessary for standard init.
-				if err := json.NewEncoder(pipe).Encode(procError); err != nil {
+				if err := utils.WriteJSON(pipe, syncT{procError}); err != nil {
 					panic(err)
 				}
 			}
-			if err := json.NewEncoder(pipe).Encode(newSystemError(err)); err != nil {
+			if err := utils.WriteJSON(pipe, newSystemError(err)); err != nil {
 				panic(err)
 			}
 		} else {
-			if err := json.NewEncoder(pipe).Encode(procStart); err != nil {
+			if err := utils.WriteJSON(pipe, syncT{procStart}); err != nil {
 				panic(err)
 			}
 		}
diff --git a/libcontainer/factory_linux_test.go b/libcontainer/factory_linux_test.go
index dccc8db..b0c0f49 100644
--- a/libcontainer/factory_linux_test.go
+++ b/libcontainer/factory_linux_test.go
@@ -3,7 +3,6 @@
 package libcontainer
 
 import (
-	"encoding/json"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -12,6 +11,7 @@
 
 	"github.com/docker/docker/pkg/mount"
 	"github.com/opencontainers/runc/libcontainer/configs"
+	"github.com/opencontainers/runc/libcontainer/utils"
 )
 
 func newTestRoot() (string, error) {
@@ -179,5 +179,5 @@
 		return err
 	}
 	defer f.Close()
-	return json.NewEncoder(f).Encode(v)
+	return utils.WriteJSON(f, v)
 }
diff --git a/libcontainer/generic_error.go b/libcontainer/generic_error.go
index e4872e2..924d637 100644
--- a/libcontainer/generic_error.go
+++ b/libcontainer/generic_error.go
@@ -18,6 +18,10 @@
 	procRun
 )
 
+type syncT struct {
+	Type syncType `json:"type"`
+}
+
 var errorTemplate = template.Must(template.New("error").Parse(`Timestamp: {{.Timestamp}}
 Code: {{.ECode}}
 {{if .Message }}
diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go
index 57e5378..918f103 100644
--- a/libcontainer/init_linux.go
+++ b/libcontainer/init_linux.go
@@ -147,17 +147,16 @@
 // indicate that it is cleared to Exec.
 func syncParentReady(pipe io.ReadWriter) error {
 	// Tell parent.
-	if err := json.NewEncoder(pipe).Encode(procReady); err != nil {
+	if err := utils.WriteJSON(pipe, syncT{procReady}); err != nil {
 		return err
 	}
-
 	// Wait for parent to give the all-clear.
-	var procSync syncType
+	var procSync syncT
 	if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
 		if err == io.EOF {
 			return fmt.Errorf("parent closed synchronisation channel")
 		}
-		if procSync != procRun {
+		if procSync.Type != procRun {
 			return fmt.Errorf("invalid synchronisation flag from parent")
 		}
 	}
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 1a6dc12..ac457c2 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -16,6 +16,7 @@
 	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/system"
+	"github.com/opencontainers/runc/libcontainer/utils"
 )
 
 type parentProcess interface {
@@ -84,7 +85,7 @@
 			return newSystemError(err)
 		}
 	}
-	if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
+	if err := utils.WriteJSON(p.parentPipe, p.config); err != nil {
 		return newSystemError(err)
 	}
 
@@ -231,9 +232,8 @@
 	if err := p.sendConfig(); err != nil {
 		return newSystemError(err)
 	}
-
 	var (
-		procSync syncType
+		procSync syncT
 		sentRun  bool
 		ierr     *genericError
 	)
@@ -246,8 +246,7 @@
 			}
 			return newSystemError(err)
 		}
-
-		switch procSync {
+		switch procSync.Type {
 		case procStart:
 			break loop
 		case procReady:
@@ -255,7 +254,7 @@
 				return newSystemError(err)
 			}
 			// Sync with child.
-			if err := json.NewEncoder(p.parentPipe).Encode(procRun); err != nil {
+			if err := utils.WriteJSON(p.parentPipe, syncT{procRun}); err != nil {
 				return newSystemError(err)
 			}
 			sentRun = true
@@ -317,10 +316,7 @@
 
 func (p *initProcess) sendConfig() error {
 	// send the state to the container's init process then shutdown writes for the parent
-	if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
-		return err
-	}
-	return nil
+	return utils.WriteJSON(p.parentPipe, p.config)
 }
 
 func (p *initProcess) createNetworkInterfaces() error {
diff --git a/libcontainer/utils/utils.go b/libcontainer/utils/utils.go
index 86cf1d6..1378006 100644
--- a/libcontainer/utils/utils.go
+++ b/libcontainer/utils/utils.go
@@ -3,6 +3,7 @@
 import (
 	"crypto/rand"
 	"encoding/hex"
+	"encoding/json"
 	"io"
 	"path/filepath"
 	"syscall"
@@ -36,10 +37,20 @@
 }
 
 // ExitStatus returns the correct exit status for a process based on if it
-// was signaled or exited cleanly.
+// was signaled or exited cleanly
 func ExitStatus(status syscall.WaitStatus) int {
 	if status.Signaled() {
 		return exitSignalOffset + int(status.Signal())
 	}
 	return status.ExitStatus()
 }
+
+// WriteJSON writes the provided struct v to w using standard json marshaling
+func WriteJSON(w io.Writer, v interface{}) error {
+	data, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+	_, err = w.Write(data)
+	return err
+}