Browse Source

Merge pull request #2827 from dotcloud/2778-fix-shell-corrupt

2778 fix shell corrupt
Guillaume J. Charmes 11 years ago
parent
commit
ba6dd1d8d6
2 changed files with 43 additions and 35 deletions
  1. 1 1
      buildfile.go
  2. 42 34
      commands.go

+ 1 - 1
buildfile.go

@@ -241,7 +241,7 @@ func (b *buildFile) CmdVolume(args string) error {
 		volume = []string{args}
 		volume = []string{args}
 	}
 	}
 	if b.config.Volumes == nil {
 	if b.config.Volumes == nil {
-		b.config.Volumes = NewPathOpts()
+		b.config.Volumes = PathOpts{}
 	}
 	}
 	for _, v := range volume {
 	for _, v := range volume {
 		b.config.Volumes[v] = struct{}{}
 		b.config.Volumes[v] = struct{}{}

+ 42 - 34
commands.go

@@ -1632,15 +1632,7 @@ type ports []int
 // AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
 // AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
 type AttachOpts map[string]bool
 type AttachOpts map[string]bool
 
 
-func NewAttachOpts() AttachOpts {
-	return make(AttachOpts)
-}
-
-func (opts AttachOpts) String() string {
-	// Cast to underlying map type to avoid infinite recursion
-	return fmt.Sprintf("%v", map[string]bool(opts))
-}
-
+func (opts AttachOpts) String() string { return fmt.Sprintf("%v", map[string]bool(opts)) }
 func (opts AttachOpts) Set(val string) error {
 func (opts AttachOpts) Set(val string) error {
 	if val != "stdin" && val != "stdout" && val != "stderr" {
 	if val != "stdin" && val != "stdout" && val != "stderr" {
 		return fmt.Errorf("Unsupported stream name: %s", val)
 		return fmt.Errorf("Unsupported stream name: %s", val)
@@ -1649,24 +1641,21 @@ func (opts AttachOpts) Set(val string) error {
 	return nil
 	return nil
 }
 }
 
 
-func (opts AttachOpts) Get(val string) bool {
-	if res, exists := opts[val]; exists {
-		return res
+// LinkOpts stores arguments to `docker run -link`
+type LinkOpts []string
+
+func (link LinkOpts) String() string { return fmt.Sprintf("%v", []string(link)) }
+func (link LinkOpts) Set(val string) error {
+	if _, err := parseLink(val); err != nil {
+		return err
 	}
 	}
-	return false
+	return nil
 }
 }
 
 
 // PathOpts stores a unique set of absolute paths
 // PathOpts stores a unique set of absolute paths
 type PathOpts map[string]struct{}
 type PathOpts map[string]struct{}
 
 
-func NewPathOpts() PathOpts {
-	return make(PathOpts)
-}
-
-func (opts PathOpts) String() string {
-	return fmt.Sprintf("%v", map[string]struct{}(opts))
-}
-
+func (opts PathOpts) String() string { return fmt.Sprintf("%v", map[string]struct{}(opts)) }
 func (opts PathOpts) Set(val string) error {
 func (opts PathOpts) Set(val string) error {
 	var containerPath string
 	var containerPath string
 
 
@@ -1732,8 +1721,9 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Config, *HostConfig, *flag.FlagSet, error) {
 func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Config, *HostConfig, *flag.FlagSet, error) {
 	var (
 	var (
 		// FIXME: use utils.ListOpts for attach and volumes?
 		// FIXME: use utils.ListOpts for attach and volumes?
-		flAttach  = NewAttachOpts()
-		flVolumes = NewPathOpts()
+		flAttach  = AttachOpts{}
+		flVolumes = PathOpts{}
+		flLinks   = LinkOpts{}
 
 
 		flPublish     utils.ListOpts
 		flPublish     utils.ListOpts
 		flExpose      utils.ListOpts
 		flExpose      utils.ListOpts
@@ -1741,7 +1731,6 @@ func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Co
 		flDns         utils.ListOpts
 		flDns         utils.ListOpts
 		flVolumesFrom utils.ListOpts
 		flVolumesFrom utils.ListOpts
 		flLxcOpts     utils.ListOpts
 		flLxcOpts     utils.ListOpts
-		flLinks       utils.ListOpts
 
 
 		flAutoRemove      = cmd.Bool("rm", false, "Automatically remove the container when it exits (incompatible with -d)")
 		flAutoRemove      = cmd.Bool("rm", false, "Automatically remove the container when it exits (incompatible with -d)")
 		flDetach          = cmd.Bool("d", false, "Detached mode: Run container in the background, print new container id")
 		flDetach          = cmd.Bool("d", false, "Detached mode: Run container in the background, print new container id")
@@ -1765,6 +1754,7 @@ func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Co
 
 
 	cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
 	cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
 	cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
 	cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
+	cmd.Var(flLinks, "link", "Add link to another container (name:alias)")
 
 
 	cmd.Var(&flPublish, "p", fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", PortSpecTemplateFormat))
 	cmd.Var(&flPublish, "p", fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", PortSpecTemplateFormat))
 	cmd.Var(&flExpose, "expose", "Expose a port from the container without publishing it to your host")
 	cmd.Var(&flExpose, "expose", "Expose a port from the container without publishing it to your host")
@@ -1772,7 +1762,6 @@ func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Co
 	cmd.Var(&flDns, "dns", "Set custom dns servers")
 	cmd.Var(&flDns, "dns", "Set custom dns servers")
 	cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
 	cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
 	cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
 	cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
-	cmd.Var(&flLinks, "link", "Add link to another container (name:alias)")
 
 
 	if err := cmd.Parse(args); err != nil {
 	if err := cmd.Parse(args); err != nil {
 		return nil, nil, cmd, err
 		return nil, nil, cmd, err
@@ -1898,9 +1887,9 @@ func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Co
 		OpenStdin:       *flStdin,
 		OpenStdin:       *flStdin,
 		Memory:          flMemory,
 		Memory:          flMemory,
 		CpuShares:       *flCpuShares,
 		CpuShares:       *flCpuShares,
-		AttachStdin:     flAttach.Get("stdin"),
-		AttachStdout:    flAttach.Get("stdout"),
-		AttachStderr:    flAttach.Get("stderr"),
+		AttachStdin:     flAttach["stdin"],
+		AttachStdout:    flAttach["stdout"],
+		AttachStderr:    flAttach["stderr"],
 		Env:             envs,
 		Env:             envs,
 		Cmd:             runCmd,
 		Cmd:             runCmd,
 		Dns:             flDns,
 		Dns:             flDns,
@@ -2053,9 +2042,18 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 		}()
 		}()
 	}
 	}
 
 
-	// We need to make the chan because the select needs to have a closing
-	// chan, it can't be uninitialized
-	hijacked := make(chan bool)
+	// We need to instanciate the chan because the select needs it. It can
+	// be closed but can't be uninitialized.
+	hijacked := make(chan io.Closer)
+
+	// Block the return until the chan gets closed
+	defer func() {
+		utils.Debugf("End of CmdRun(), Waiting for hijack to finish.")
+		if _, ok := <-hijacked; ok {
+			utils.Errorf("Hijack did not finish (chan still open)")
+		}
+	}()
+
 	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
 	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
 		var (
 		var (
 			out, stderr io.Writer
 			out, stderr io.Writer
@@ -2090,7 +2088,12 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 
 
 	// Acknowledge the hijack before starting
 	// Acknowledge the hijack before starting
 	select {
 	select {
-	case <-hijacked:
+	case closer := <-hijacked:
+		// Make sure that hijack gets closed when returning. (result
+		// in closing hijack chan and freeing server's goroutines.
+		if closer != nil {
+			defer closer.Close()
+		}
 	case err := <-errCh:
 	case err := <-errCh:
 		if err != nil {
 		if err != nil {
 			utils.Debugf("Error hijack: %s", err)
 			utils.Debugf("Error hijack: %s", err)
@@ -2339,7 +2342,12 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
 	return nil
 	return nil
 }
 }
 
 
-func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan bool) error {
+func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error {
+	defer func() {
+		if started != nil {
+			close(started)
+		}
+	}()
 	// fixme: refactor client to support redirect
 	// fixme: refactor client to support redirect
 	re := regexp.MustCompile("/+")
 	re := regexp.MustCompile("/+")
 	path = re.ReplaceAllString(path, "/")
 	path = re.ReplaceAllString(path, "/")
@@ -2369,7 +2377,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
 	defer rwc.Close()
 	defer rwc.Close()
 
 
 	if started != nil {
 	if started != nil {
-		started <- true
+		started <- rwc
 	}
 	}
 
 
 	var receiveStdout chan error
 	var receiveStdout chan error