text: package client
  
  import (
  	"fmt"
  	"io"
  	"net/url"
  	"os"
  	"runtime"
  
  	"github.com/Sirupsen/logrus"
  	Cli "github.com/docker/docker/cli"
  	"github.com/docker/docker/opts"
  	"github.com/docker/docker/pkg/promise"
  	"github.com/docker/docker/pkg/signal"
  	"github.com/docker/docker/runconfig"
  	"github.com/docker/libnetwork/resolvconf/dns"
  )
  
  func (cid *cidFile) Close() error {
  	cid.file.Close()
  
  	if !cid.written {
  		if err := os.Remove(cid.path); err != nil {
  			return fmt.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
  		}
  	}
  
  	return nil
  }
  
  func (cid *cidFile) Write(id string) error {
  	if _, err := cid.file.Write([]byte(id)); err != nil {
  		return fmt.Errorf("Failed to write the container ID to the file: %s", err)
  	}
  	cid.written = true
  	return nil
  }
  
  // CmdRun runs a command in a new container.
  //
  // Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  func (cli *DockerCli) CmdRun(args ...string) error {
  	cmd := Cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true)
  	addTrustedFlags(cmd, true)
  
  	// These are flags not stored in Config/HostConfig
  	var (
  		flAutoRemove = cmd.Bool([]string{"-rm"}, false, "Automatically remove the container when it exits")
  		flDetach     = cmd.Bool([]string{"d", "-detach"}, false, "Run container in background and print container ID")
  		flSigProxy   = cmd.Bool([]string{"-sig-proxy"}, true, "Proxy received signals to the process")
  		flName       = cmd.String([]string{"-name"}, "", "Assign a name to the container")
  		flAttach     *opts.ListOpts
  
  		ErrConflictAttachDetach               = fmt.Errorf("Conflicting options: -a and -d")
  		ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
  		ErrConflictDetachAutoRemove           = fmt.Errorf("Conflicting options: --rm and -d")
  	)
  
  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  	// just in case the Parse does not exit
  	if err != nil {
  		cmd.ReportError(err.Error(), true)
  		os.Exit(1)
  	}
  
  	if len(hostConfig.Dns) > 0 {
  		// check the DNS settings passed via --dns against
  		// localhost regexp to warn if they are trying to
  		// set a DNS to a localhost address
  		for _, dnsIP := range hostConfig.Dns {
  			if dns.IsLocalhost(dnsIP) {
  				fmt.Fprintf(cli.err, "WARNING: Localhost DNS setting (--dns=%s) may fail in containers.\n", dnsIP)
  				break
  			}
  		}
  	}
  	if config.Image == "" {
  		cmd.Usage()
  		return nil
  	}
  
  	if !*flDetach {
  		if err := cli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil {
  			return err
  		}
  	} else {
  		if fl := cmd.Lookup("-attach"); fl != nil {
  			flAttach = fl.Value.(*opts.ListOpts)
  			if flAttach.Len() != 0 {
  				return ErrConflictAttachDetach
  			}
  		}
  		if *flAutoRemove {
  			return ErrConflictDetachAutoRemove
  		}
  
  		config.AttachStdin = false
  		config.AttachStdout = false
  		config.AttachStderr = false
  		config.StdinOnce = false
  	}
  
  	// Disable flSigProxy when in TTY mode
  	sigProxy := *flSigProxy
  	if config.Tty {
  		sigProxy = false
  	}
  
  	// Telling the Windows daemon the initial size of the tty during start makes
  	// a far better user experience rather than relying on subsequent resizes
  	// to cause things to catch up.
  	if runtime.GOOS == "windows" {
  		hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = cli.getTtySize()
  	}
  
  	createResponse, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  	if err != nil {
  		return err
  	}
  	if sigProxy {
  		sigc := cli.forwardAllSignals(createResponse.ID)
  		defer signal.StopCatch(sigc)
  	}
  	var (
  		waitDisplayID chan struct{}
  		errCh         chan error
  	)
  	if !config.AttachStdout && !config.AttachStderr {
  		// Make this asynchronous to allow the client to write to stdin before having to read the ID
  		waitDisplayID = make(chan struct{})
  		go func() {
  			defer close(waitDisplayID)
  			fmt.Fprintf(cli.out, "%s\n", createResponse.ID)
  		}()
  	}
  	if *flAutoRemove && (hostConfig.RestartPolicy.IsAlways() || hostConfig.RestartPolicy.IsOnFailure()) {
  		return ErrConflictRestartPolicyAndAutoRemove
  	}
  	// We need to instantiate 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() {
  		logrus.Debugf("End of CmdRun(), Waiting for hijack to finish.")
  		if _, ok := <-hijacked; ok {
  			fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)")
  		}
  	}()
  	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
  		var (
  			out, stderr io.Writer
  			in          io.ReadCloser
  			v           = url.Values{}
  		)
  		v.Set("stream", "1")
  		if config.AttachStdin {
  			v.Set("stdin", "1")
  			in = cli.in
  		}
  		if config.AttachStdout {
  			v.Set("stdout", "1")
  			out = cli.out
  		}
  		if config.AttachStderr {
  			v.Set("stderr", "1")
  			if config.Tty {
  				stderr = cli.out
  			} else {
  				stderr = cli.err
  			}
  		}
  		errCh = promise.Go(func() error {
  			return cli.hijack("POST", "/containers/"+createResponse.ID+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked, nil)
  		})
  	} else {
  		close(hijacked)
  	}
  	// Acknowledge the hijack before starting
  	select {
  	case closer := <-hijacked:
  		// Make sure that the hijack gets closed when returning (results
  		// in closing the hijack chan and freeing server's goroutines)
  		if closer != nil {
  			defer closer.Close()
  		}
  	case err := <-errCh:
  		if err != nil {
  			logrus.Debugf("Error hijack: %s", err)
  			return err
  		}
  	}
  
  	defer func() {
  		if *flAutoRemove {
  			if _, _, err = readBody(cli.call("DELETE", "/containers/"+createResponse.ID+"?v=1", nil, nil)); err != nil {
  				fmt.Fprintf(cli.err, "Error deleting container: %s\n", err)
  			}
  		}
  	}()
  
  	//start the container
  	if _, _, err = readBody(cli.call("POST", "/containers/"+createResponse.ID+"/start", nil, nil)); err != nil {
  		return err
  	}
  
  	if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminalOut {
  		if err := cli.monitorTtySize(createResponse.ID, false); err != nil {
  			fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
  		}
  	}
  
  	if errCh != nil {
  		if err := <-errCh; err != nil {
  			logrus.Debugf("Error hijack: %s", err)
  			return err
  		}
  	}
  
  	// Detached mode: wait for the id to be displayed and return.
  	if !config.AttachStdout && !config.AttachStderr {
  		// Detached mode
  		<-waitDisplayID
  		return nil
  	}
  
  	var status int
  
  	// Attached mode
  	if *flAutoRemove {
  		// Autoremove: wait for the container to finish, retrieve
  		// the exit code and remove the container
  		if _, _, err := readBody(cli.call("POST", "/containers/"+createResponse.ID+"/wait", nil, nil)); err != nil {
  			return err
  		}
  		if _, status, err = getExitCode(cli, createResponse.ID); err != nil {
  			return err
  		}
  	} else {
  		// No Autoremove: Simply retrieve the exit code
  		if !config.Tty {
  			// In non-TTY mode, we can't detach, so we must wait for container exit
  			if status, err = waitForExit(cli, createResponse.ID); err != nil {
  				return err
  			}
  		} else {
  			// In TTY mode, there is a race: if the process dies too slowly, the state could
  			// be updated after the getExitCode call and result in the wrong exit code being reported
  			if _, status, err = getExitCode(cli, createResponse.ID); err != nil {
  				return err
  			}
  		}
  	}
  	if status != 0 {
  		return Cli.StatusError{StatusCode: status}
  	}
  	return nil
  }
  