Merge pull request #2242 from jpetazzo/remove-spurious-errors-and-errclosedpipe

Fix error/debug messages in Container.Attach and recover from ErrClosedPipe
diff --git a/container.go b/container.go
index 51313eb..7d85aef 100644
--- a/container.go
+++ b/container.go
@@ -390,9 +390,9 @@
 	// Copy the PTYs to our broadcasters
 	go func() {
 		defer container.stdout.CloseWriters()
-		utils.Debugf("[startPty] Begin of stdout pipe")
+		utils.Debugf("startPty: begin of stdout pipe")
 		io.Copy(container.stdout, ptyMaster)
-		utils.Debugf("[startPty] End of stdout pipe")
+		utils.Debugf("startPty: end of stdout pipe")
 	}()
 
 	// stdin
@@ -401,9 +401,9 @@
 		container.cmd.SysProcAttr.Setctty = true
 		go func() {
 			defer container.stdin.Close()
-			utils.Debugf("[startPty] Begin of stdin pipe")
+			utils.Debugf("startPty: begin of stdin pipe")
 			io.Copy(ptyMaster, container.stdin)
-			utils.Debugf("[startPty] End of stdin pipe")
+			utils.Debugf("startPty: end of stdin pipe")
 		}()
 	}
 	if err := container.cmd.Start(); err != nil {
@@ -423,9 +423,9 @@
 		}
 		go func() {
 			defer stdin.Close()
-			utils.Debugf("Begin of stdin pipe [start]")
+			utils.Debugf("start: begin of stdin pipe")
 			io.Copy(stdin, container.stdin)
-			utils.Debugf("End of stdin pipe [start]")
+			utils.Debugf("start: end of stdin pipe")
 		}()
 	}
 	return container.cmd.Start()
@@ -442,8 +442,8 @@
 			errors <- err
 		} else {
 			go func() {
-				utils.Debugf("[start] attach stdin\n")
-				defer utils.Debugf("[end] attach stdin\n")
+				utils.Debugf("attach: stdin: begin")
+				defer utils.Debugf("attach: stdin: end")
 				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
 				if container.Config.StdinOnce && !container.Config.Tty {
 					defer cStdin.Close()
@@ -461,7 +461,7 @@
 					_, err = io.Copy(cStdin, stdin)
 				}
 				if err != nil {
-					utils.Errorf("[error] attach stdin: %s\n", err)
+					utils.Errorf("attach: stdin: %s", err)
 				}
 				// Discard error, expecting pipe error
 				errors <- nil
@@ -475,8 +475,8 @@
 		} else {
 			cStdout = p
 			go func() {
-				utils.Debugf("[start] attach stdout\n")
-				defer utils.Debugf("[end]  attach stdout\n")
+				utils.Debugf("attach: stdout: begin")
+				defer utils.Debugf("attach: stdout: end")
 				// If we are in StdinOnce mode, then close stdin
 				if container.Config.StdinOnce && stdin != nil {
 					defer stdin.Close()
@@ -485,8 +485,11 @@
 					defer stdinCloser.Close()
 				}
 				_, err := io.Copy(stdout, cStdout)
+				if err == io.ErrClosedPipe {
+					err = nil
+				}
 				if err != nil {
-					utils.Errorf("[error] attach stdout: %s\n", err)
+					utils.Errorf("attach: stdout: %s", err)
 				}
 				errors <- err
 			}()
@@ -496,9 +499,8 @@
 			if stdinCloser != nil {
 				defer stdinCloser.Close()
 			}
-
 			if cStdout, err := container.StdoutPipe(); err != nil {
-				utils.Errorf("Error stdout pipe")
+				utils.Errorf("attach: stdout pipe: %s", err)
 			} else {
 				io.Copy(&utils.NopWriter{}, cStdout)
 			}
@@ -511,8 +513,8 @@
 		} else {
 			cStderr = p
 			go func() {
-				utils.Debugf("[start] attach stderr\n")
-				defer utils.Debugf("[end]  attach stderr\n")
+				utils.Debugf("attach: stderr: begin")
+				defer utils.Debugf("attach: stderr: end")
 				// If we are in StdinOnce mode, then close stdin
 				if container.Config.StdinOnce && stdin != nil {
 					defer stdin.Close()
@@ -521,8 +523,11 @@
 					defer stdinCloser.Close()
 				}
 				_, err := io.Copy(stderr, cStderr)
+				if err == io.ErrClosedPipe {
+					err = nil
+				}
 				if err != nil {
-					utils.Errorf("[error] attach stderr: %s\n", err)
+					utils.Errorf("attach: stderr: %s", err)
 				}
 				errors <- err
 			}()
@@ -534,7 +539,7 @@
 			}
 
 			if cStderr, err := container.StderrPipe(); err != nil {
-				utils.Errorf("Error stdout pipe")
+				utils.Errorf("attach: stdout pipe: %s", err)
 			} else {
 				io.Copy(&utils.NopWriter{}, cStderr)
 			}
@@ -548,17 +553,17 @@
 		if cStderr != nil {
 			defer cStderr.Close()
 		}
-		// FIXME: how do clean up the stdin goroutine without the unwanted side effect
+		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
 		// of closing the passed stdin? Add an intermediary io.Pipe?
 		for i := 0; i < nJobs; i += 1 {
-			utils.Debugf("Waiting for job %d/%d\n", i+1, nJobs)
+			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
 			if err := <-errors; err != nil {
-				utils.Errorf("Job %d returned error %s. Aborting all jobs\n", i+1, err)
+				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
 				return err
 			}
-			utils.Debugf("Job %d completed successfully\n", i+1)
+			utils.Debugf("attach: job %d completed successfully", i+1)
 		}
-		utils.Debugf("All jobs completed successfully\n")
+		utils.Debugf("attach: all jobs completed successfully")
 		return nil
 	})
 }
@@ -853,9 +858,14 @@
 	return output, err
 }
 
-// StdinPipe() returns a pipe connected to the standard input of the container's
-// active process.
-//
+// Container.StdinPipe returns a WriteCloser which can be used to feed data
+// to the standard input of the container's active process.
+// Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
+// which can be used to retrieve the standard output (and error) generated
+// by the container's active process. The output (and error) are actually
+// copied and delivered to all StdoutPipe and StderrPipe consumers, using
+// a kind of "broadcaster".
+
 func (container *Container) StdinPipe() (io.WriteCloser, error) {
 	return container.stdinPipe, nil
 }
@@ -957,20 +967,23 @@
 
 func (container *Container) monitor(hostConfig *HostConfig) {
 	// Wait for the program to exit
-	utils.Debugf("Waiting for process")
 
-	// If the command does not exists, try to wait via lxc
+	// If the command does not exist, try to wait via lxc
+	// (This probably happens only for ghost containers, i.e. containers that were running when Docker started)
 	if container.cmd == nil {
+		utils.Debugf("monitor: waiting for container %s using waitLxc", container.ID)
 		if err := container.waitLxc(); err != nil {
-			utils.Errorf("%s: Process: %s", container.ID, err)
+			utils.Errorf("monitor: while waiting for container %s, waitLxc had a problem: %s", container.ID, err)
 		}
 	} else {
+		utils.Debugf("monitor: waiting for container %s using cmd.Wait", container.ID)
 		if err := container.cmd.Wait(); err != nil {
-			// Discard the error as any signals or non 0 returns will generate an error
-			utils.Errorf("%s: Process: %s", container.ID, err)
+			// Since non-zero exit status and signal terminations will cause err to be non-nil,
+			// we have to actually discard it. Still, log it anyway, just in case.
+			utils.Debugf("monitor: cmd.Wait reported exit status %s for container %s", err, container.ID)
 		}
 	}
-	utils.Debugf("Process finished")
+	utils.Debugf("monitor: container %s finished", container.ID)
 
 	exitCode := -1
 	if container.cmd != nil {