github.com/sbward/docker@v1.4.2-0.20150114010528-c9dab702bed3/api/client/commands.go (about)

     1  package client
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"net/url"
    14  	"os"
    15  	"os/exec"
    16  	"path"
    17  	"path/filepath"
    18  	"runtime"
    19  	"strconv"
    20  	"strings"
    21  	"text/tabwriter"
    22  	"text/template"
    23  	"time"
    24  
    25  	log "github.com/Sirupsen/logrus"
    26  	"github.com/docker/docker/api"
    27  	"github.com/docker/docker/dockerversion"
    28  	"github.com/docker/docker/engine"
    29  	"github.com/docker/docker/graph"
    30  	"github.com/docker/docker/nat"
    31  	"github.com/docker/docker/opts"
    32  	"github.com/docker/docker/pkg/archive"
    33  	"github.com/docker/docker/pkg/fileutils"
    34  	flag "github.com/docker/docker/pkg/mflag"
    35  	"github.com/docker/docker/pkg/parsers"
    36  	"github.com/docker/docker/pkg/parsers/filters"
    37  	"github.com/docker/docker/pkg/promise"
    38  	"github.com/docker/docker/pkg/signal"
    39  	"github.com/docker/docker/pkg/term"
    40  	"github.com/docker/docker/pkg/timeutils"
    41  	"github.com/docker/docker/pkg/units"
    42  	"github.com/docker/docker/pkg/urlutil"
    43  	"github.com/docker/docker/registry"
    44  	"github.com/docker/docker/runconfig"
    45  	"github.com/docker/docker/utils"
    46  )
    47  
    48  const (
    49  	tarHeaderSize = 512
    50  )
    51  
    52  var (
    53  	acceptedImageFilterTags = map[string]struct{}{"dangling": {}}
    54  )
    55  
    56  func (cli *DockerCli) CmdHelp(args ...string) error {
    57  	if len(args) > 1 {
    58  		method, exists := cli.getMethod(args[:2]...)
    59  		if exists {
    60  			method("--help")
    61  			return nil
    62  		}
    63  	}
    64  	if len(args) > 0 {
    65  		method, exists := cli.getMethod(args[0])
    66  		if !exists {
    67  			fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
    68  			os.Exit(1)
    69  		} else {
    70  			method("--help")
    71  			return nil
    72  		}
    73  	}
    74  
    75  	flag.Usage()
    76  
    77  	return nil
    78  }
    79  
    80  func (cli *DockerCli) CmdBuild(args ...string) error {
    81  	cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
    82  	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
    83  	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
    84  	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
    85  	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
    86  	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
    87  	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
    88  	dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile(Default is 'Dockerfile' at context root)")
    89  
    90  	cmd.Require(flag.Exact, 1)
    91  
    92  	utils.ParseFlags(cmd, args, true)
    93  
    94  	var (
    95  		context  archive.Archive
    96  		isRemote bool
    97  		err      error
    98  	)
    99  
   100  	_, err = exec.LookPath("git")
   101  	hasGit := err == nil
   102  	if cmd.Arg(0) == "-" {
   103  		// As a special case, 'docker build -' will build from either an empty context with the
   104  		// contents of stdin as a Dockerfile, or a tar-ed context from stdin.
   105  		buf := bufio.NewReader(cli.in)
   106  		magic, err := buf.Peek(tarHeaderSize)
   107  		if err != nil && err != io.EOF {
   108  			return fmt.Errorf("failed to peek context header from STDIN: %v", err)
   109  		}
   110  		if !archive.IsArchive(magic) {
   111  			dockerfile, err := ioutil.ReadAll(buf)
   112  			if err != nil {
   113  				return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err)
   114  			}
   115  			if *dockerfileName == "" {
   116  				*dockerfileName = api.DefaultDockerfileName
   117  			}
   118  			context, err = archive.Generate(*dockerfileName, string(dockerfile))
   119  		} else {
   120  			context = ioutil.NopCloser(buf)
   121  		}
   122  	} else if urlutil.IsURL(cmd.Arg(0)) && (!urlutil.IsGitURL(cmd.Arg(0)) || !hasGit) {
   123  		isRemote = true
   124  	} else {
   125  		root := cmd.Arg(0)
   126  		if urlutil.IsGitURL(root) {
   127  			remoteURL := cmd.Arg(0)
   128  			if !urlutil.IsGitTransport(remoteURL) {
   129  				remoteURL = "https://" + remoteURL
   130  			}
   131  
   132  			root, err = ioutil.TempDir("", "docker-build-git")
   133  			if err != nil {
   134  				return err
   135  			}
   136  			defer os.RemoveAll(root)
   137  
   138  			if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
   139  				return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
   140  			}
   141  		}
   142  		if _, err := os.Stat(root); err != nil {
   143  			return err
   144  		}
   145  
   146  		absRoot, err := filepath.Abs(root)
   147  		if err != nil {
   148  			return err
   149  		}
   150  
   151  		var filename string       // path to Dockerfile
   152  		var origDockerfile string // used for error msg
   153  
   154  		if *dockerfileName == "" {
   155  			// No -f/--file was specified so use the default
   156  			origDockerfile = api.DefaultDockerfileName
   157  			*dockerfileName = origDockerfile
   158  			filename = path.Join(absRoot, *dockerfileName)
   159  		} else {
   160  			origDockerfile = *dockerfileName
   161  			if filename, err = filepath.Abs(*dockerfileName); err != nil {
   162  				return err
   163  			}
   164  
   165  			// Verify that 'filename' is within the build context
   166  			if !strings.HasSuffix(absRoot, string(os.PathSeparator)) {
   167  				absRoot += string(os.PathSeparator)
   168  			}
   169  			if !strings.HasPrefix(filename, absRoot) {
   170  				return fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", *dockerfileName, root)
   171  			}
   172  
   173  			// Now reset the dockerfileName to be relative to the build context
   174  			*dockerfileName = filename[len(absRoot):]
   175  		}
   176  
   177  		if _, err = os.Stat(filename); os.IsNotExist(err) {
   178  			return fmt.Errorf("Can not locate Dockerfile: %s", origDockerfile)
   179  		}
   180  		var includes []string = []string{"."}
   181  
   182  		excludes, err := utils.ReadDockerIgnore(path.Join(root, ".dockerignore"))
   183  		if err != nil {
   184  			return err
   185  		}
   186  
   187  		// If .dockerignore mentions .dockerignore or the Dockerfile
   188  		// then make sure we send both files over to the daemon
   189  		// because Dockerfile is, obviously, needed no matter what, and
   190  		// .dockerignore is needed to know if either one needs to be
   191  		// removed.  The deamon will remove them for us, if needed, after it
   192  		// parses the Dockerfile.
   193  		keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
   194  		keepThem2, _ := fileutils.Matches(*dockerfileName, excludes)
   195  		if keepThem1 || keepThem2 {
   196  			includes = append(includes, ".dockerignore", *dockerfileName)
   197  		}
   198  
   199  		if err = utils.ValidateContextDirectory(root, excludes); err != nil {
   200  			return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
   201  		}
   202  		options := &archive.TarOptions{
   203  			Compression:     archive.Uncompressed,
   204  			ExcludePatterns: excludes,
   205  			IncludeFiles:    includes,
   206  		}
   207  		context, err = archive.TarWithOptions(root, options)
   208  		if err != nil {
   209  			return err
   210  		}
   211  	}
   212  	var body io.Reader
   213  	// Setup an upload progress bar
   214  	// FIXME: ProgressReader shouldn't be this annoying to use
   215  	if context != nil {
   216  		sf := utils.NewStreamFormatter(false)
   217  		body = utils.ProgressReader(context, 0, cli.out, sf, true, "", "Sending build context to Docker daemon")
   218  	}
   219  	// Send the build context
   220  	v := &url.Values{}
   221  
   222  	//Check if the given image name can be resolved
   223  	if *tag != "" {
   224  		repository, tag := parsers.ParseRepositoryTag(*tag)
   225  		if err := registry.ValidateRepositoryName(repository); err != nil {
   226  			return err
   227  		}
   228  		if len(tag) > 0 {
   229  			if err := graph.ValidateTagName(tag); err != nil {
   230  				return err
   231  			}
   232  		}
   233  	}
   234  
   235  	v.Set("t", *tag)
   236  
   237  	if *suppressOutput {
   238  		v.Set("q", "1")
   239  	}
   240  	if isRemote {
   241  		v.Set("remote", cmd.Arg(0))
   242  	}
   243  	if *noCache {
   244  		v.Set("nocache", "1")
   245  	}
   246  	if *rm {
   247  		v.Set("rm", "1")
   248  	} else {
   249  		v.Set("rm", "0")
   250  	}
   251  
   252  	if *forceRm {
   253  		v.Set("forcerm", "1")
   254  	}
   255  
   256  	if *pull {
   257  		v.Set("pull", "1")
   258  	}
   259  
   260  	v.Set("dockerfile", *dockerfileName)
   261  
   262  	cli.LoadConfigFile()
   263  
   264  	headers := http.Header(make(map[string][]string))
   265  	buf, err := json.Marshal(cli.configFile)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
   270  
   271  	if context != nil {
   272  		headers.Set("Content-Type", "application/tar")
   273  	}
   274  	err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
   275  	if jerr, ok := err.(*utils.JSONError); ok {
   276  		// If no error code is set, default to 1
   277  		if jerr.Code == 0 {
   278  			jerr.Code = 1
   279  		}
   280  		return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
   281  	}
   282  	return err
   283  }
   284  
   285  // 'docker login': login / register a user to registry service.
   286  func (cli *DockerCli) CmdLogin(args ...string) error {
   287  	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
   288  	cmd.Require(flag.Max, 1)
   289  
   290  	var username, password, email string
   291  
   292  	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
   293  	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
   294  	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
   295  
   296  	utils.ParseFlags(cmd, args, true)
   297  
   298  	serverAddress := registry.IndexServerAddress()
   299  	if len(cmd.Args()) > 0 {
   300  		serverAddress = cmd.Arg(0)
   301  	}
   302  
   303  	promptDefault := func(prompt string, configDefault string) {
   304  		if configDefault == "" {
   305  			fmt.Fprintf(cli.out, "%s: ", prompt)
   306  		} else {
   307  			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
   308  		}
   309  	}
   310  
   311  	readInput := func(in io.Reader, out io.Writer) string {
   312  		reader := bufio.NewReader(in)
   313  		line, _, err := reader.ReadLine()
   314  		if err != nil {
   315  			fmt.Fprintln(out, err.Error())
   316  			os.Exit(1)
   317  		}
   318  		return string(line)
   319  	}
   320  
   321  	cli.LoadConfigFile()
   322  	authconfig, ok := cli.configFile.Configs[serverAddress]
   323  	if !ok {
   324  		authconfig = registry.AuthConfig{}
   325  	}
   326  
   327  	if username == "" {
   328  		promptDefault("Username", authconfig.Username)
   329  		username = readInput(cli.in, cli.out)
   330  		if username == "" {
   331  			username = authconfig.Username
   332  		}
   333  	}
   334  	// Assume that a different username means they may not want to use
   335  	// the password or email from the config file, so prompt them
   336  	if username != authconfig.Username {
   337  		if password == "" {
   338  			oldState, err := term.SaveState(cli.inFd)
   339  			if err != nil {
   340  				return err
   341  			}
   342  			fmt.Fprintf(cli.out, "Password: ")
   343  			term.DisableEcho(cli.inFd, oldState)
   344  
   345  			password = readInput(cli.in, cli.out)
   346  			fmt.Fprint(cli.out, "\n")
   347  
   348  			term.RestoreTerminal(cli.inFd, oldState)
   349  			if password == "" {
   350  				return fmt.Errorf("Error : Password Required")
   351  			}
   352  		}
   353  
   354  		if email == "" {
   355  			promptDefault("Email", authconfig.Email)
   356  			email = readInput(cli.in, cli.out)
   357  			if email == "" {
   358  				email = authconfig.Email
   359  			}
   360  		}
   361  	} else {
   362  		// However, if they don't override the username use the
   363  		// password or email from the cmd line if specified. IOW, allow
   364  		// then to change/overide them.  And if not specified, just
   365  		// use what's in the config file
   366  		if password == "" {
   367  			password = authconfig.Password
   368  		}
   369  		if email == "" {
   370  			email = authconfig.Email
   371  		}
   372  	}
   373  	authconfig.Username = username
   374  	authconfig.Password = password
   375  	authconfig.Email = email
   376  	authconfig.ServerAddress = serverAddress
   377  	cli.configFile.Configs[serverAddress] = authconfig
   378  
   379  	stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)
   380  	if statusCode == 401 {
   381  		delete(cli.configFile.Configs, serverAddress)
   382  		registry.SaveConfig(cli.configFile)
   383  		return err
   384  	}
   385  	if err != nil {
   386  		return err
   387  	}
   388  	var out2 engine.Env
   389  	err = out2.Decode(stream)
   390  	if err != nil {
   391  		cli.configFile, _ = registry.LoadConfig(os.Getenv("HOME"))
   392  		return err
   393  	}
   394  	registry.SaveConfig(cli.configFile)
   395  	if out2.Get("Status") != "" {
   396  		fmt.Fprintf(cli.out, "%s\n", out2.Get("Status"))
   397  	}
   398  	return nil
   399  }
   400  
   401  // log out from a Docker registry
   402  func (cli *DockerCli) CmdLogout(args ...string) error {
   403  	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
   404  	cmd.Require(flag.Max, 1)
   405  
   406  	utils.ParseFlags(cmd, args, false)
   407  	serverAddress := registry.IndexServerAddress()
   408  	if len(cmd.Args()) > 0 {
   409  		serverAddress = cmd.Arg(0)
   410  	}
   411  
   412  	cli.LoadConfigFile()
   413  	if _, ok := cli.configFile.Configs[serverAddress]; !ok {
   414  		fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
   415  	} else {
   416  		fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
   417  		delete(cli.configFile.Configs, serverAddress)
   418  
   419  		if err := registry.SaveConfig(cli.configFile); err != nil {
   420  			return fmt.Errorf("Failed to save docker config: %v", err)
   421  		}
   422  	}
   423  	return nil
   424  }
   425  
   426  // 'docker wait': block until a container stops
   427  func (cli *DockerCli) CmdWait(args ...string) error {
   428  	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
   429  	cmd.Require(flag.Min, 1)
   430  
   431  	utils.ParseFlags(cmd, args, true)
   432  
   433  	var encounteredError error
   434  	for _, name := range cmd.Args() {
   435  		status, err := waitForExit(cli, name)
   436  		if err != nil {
   437  			fmt.Fprintf(cli.err, "%s\n", err)
   438  			encounteredError = fmt.Errorf("Error: failed to wait one or more containers")
   439  		} else {
   440  			fmt.Fprintf(cli.out, "%d\n", status)
   441  		}
   442  	}
   443  	return encounteredError
   444  }
   445  
   446  // 'docker version': show version information
   447  func (cli *DockerCli) CmdVersion(args ...string) error {
   448  	cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
   449  	cmd.Require(flag.Exact, 0)
   450  
   451  	utils.ParseFlags(cmd, args, false)
   452  
   453  	if dockerversion.VERSION != "" {
   454  		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
   455  	}
   456  	fmt.Fprintf(cli.out, "Client API version: %s\n", api.APIVERSION)
   457  	fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
   458  	if dockerversion.GITCOMMIT != "" {
   459  		fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
   460  	}
   461  	fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
   462  
   463  	body, _, err := readBody(cli.call("GET", "/version", nil, false))
   464  	if err != nil {
   465  		return err
   466  	}
   467  
   468  	out := engine.NewOutput()
   469  	remoteVersion, err := out.AddEnv()
   470  	if err != nil {
   471  		log.Errorf("Error reading remote version: %s", err)
   472  		return err
   473  	}
   474  	if _, err := out.Write(body); err != nil {
   475  		log.Errorf("Error reading remote version: %s", err)
   476  		return err
   477  	}
   478  	out.Close()
   479  	fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
   480  	if apiVersion := remoteVersion.Get("ApiVersion"); apiVersion != "" {
   481  		fmt.Fprintf(cli.out, "Server API version: %s\n", apiVersion)
   482  	}
   483  	fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
   484  	fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
   485  	return nil
   486  }
   487  
   488  // 'docker info': display system-wide information.
   489  func (cli *DockerCli) CmdInfo(args ...string) error {
   490  	cmd := cli.Subcmd("info", "", "Display system-wide information", true)
   491  	cmd.Require(flag.Exact, 0)
   492  	utils.ParseFlags(cmd, args, false)
   493  
   494  	body, _, err := readBody(cli.call("GET", "/info", nil, false))
   495  	if err != nil {
   496  		return err
   497  	}
   498  
   499  	out := engine.NewOutput()
   500  	remoteInfo, err := out.AddEnv()
   501  	if err != nil {
   502  		return err
   503  	}
   504  
   505  	if _, err := out.Write(body); err != nil {
   506  		log.Errorf("Error reading remote info: %s", err)
   507  		return err
   508  	}
   509  	out.Close()
   510  
   511  	if remoteInfo.Exists("Containers") {
   512  		fmt.Fprintf(cli.out, "Containers: %d\n", remoteInfo.GetInt("Containers"))
   513  	}
   514  	if remoteInfo.Exists("Images") {
   515  		fmt.Fprintf(cli.out, "Images: %d\n", remoteInfo.GetInt("Images"))
   516  	}
   517  	if remoteInfo.Exists("Driver") {
   518  		fmt.Fprintf(cli.out, "Storage Driver: %s\n", remoteInfo.Get("Driver"))
   519  	}
   520  	if remoteInfo.Exists("DriverStatus") {
   521  		var driverStatus [][2]string
   522  		if err := remoteInfo.GetJson("DriverStatus", &driverStatus); err != nil {
   523  			return err
   524  		}
   525  		for _, pair := range driverStatus {
   526  			fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
   527  		}
   528  	}
   529  	if remoteInfo.Exists("ExecutionDriver") {
   530  		fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
   531  	}
   532  	if remoteInfo.Exists("KernelVersion") {
   533  		fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
   534  	}
   535  	if remoteInfo.Exists("OperatingSystem") {
   536  		fmt.Fprintf(cli.out, "Operating System: %s\n", remoteInfo.Get("OperatingSystem"))
   537  	}
   538  	if remoteInfo.Exists("NCPU") {
   539  		fmt.Fprintf(cli.out, "CPUs: %d\n", remoteInfo.GetInt("NCPU"))
   540  	}
   541  	if remoteInfo.Exists("MemTotal") {
   542  		fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(remoteInfo.GetInt64("MemTotal"))))
   543  	}
   544  	if remoteInfo.Exists("Name") {
   545  		fmt.Fprintf(cli.out, "Name: %s\n", remoteInfo.Get("Name"))
   546  	}
   547  	if remoteInfo.Exists("ID") {
   548  		fmt.Fprintf(cli.out, "ID: %s\n", remoteInfo.Get("ID"))
   549  	}
   550  
   551  	if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
   552  		if remoteInfo.Exists("Debug") {
   553  			fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
   554  		}
   555  		fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
   556  		if remoteInfo.Exists("NFd") {
   557  			fmt.Fprintf(cli.out, "Fds: %d\n", remoteInfo.GetInt("NFd"))
   558  		}
   559  		if remoteInfo.Exists("NGoroutines") {
   560  			fmt.Fprintf(cli.out, "Goroutines: %d\n", remoteInfo.GetInt("NGoroutines"))
   561  		}
   562  		if remoteInfo.Exists("NEventsListener") {
   563  			fmt.Fprintf(cli.out, "EventsListeners: %d\n", remoteInfo.GetInt("NEventsListener"))
   564  		}
   565  		if initSha1 := remoteInfo.Get("InitSha1"); initSha1 != "" {
   566  			fmt.Fprintf(cli.out, "Init SHA1: %s\n", initSha1)
   567  		}
   568  		if initPath := remoteInfo.Get("InitPath"); initPath != "" {
   569  			fmt.Fprintf(cli.out, "Init Path: %s\n", initPath)
   570  		}
   571  		if root := remoteInfo.Get("DockerRootDir"); root != "" {
   572  			fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", root)
   573  		}
   574  	}
   575  
   576  	if len(remoteInfo.GetList("IndexServerAddress")) != 0 {
   577  		cli.LoadConfigFile()
   578  		u := cli.configFile.Configs[remoteInfo.Get("IndexServerAddress")].Username
   579  		if len(u) > 0 {
   580  			fmt.Fprintf(cli.out, "Username: %v\n", u)
   581  			fmt.Fprintf(cli.out, "Registry: %v\n", remoteInfo.GetList("IndexServerAddress"))
   582  		}
   583  	}
   584  	if remoteInfo.Exists("MemoryLimit") && !remoteInfo.GetBool("MemoryLimit") {
   585  		fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
   586  	}
   587  	if remoteInfo.Exists("SwapLimit") && !remoteInfo.GetBool("SwapLimit") {
   588  		fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
   589  	}
   590  	if remoteInfo.Exists("IPv4Forwarding") && !remoteInfo.GetBool("IPv4Forwarding") {
   591  		fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
   592  	}
   593  	if remoteInfo.Exists("Labels") {
   594  		fmt.Fprintln(cli.out, "Labels:")
   595  		for _, attribute := range remoteInfo.GetList("Labels") {
   596  			fmt.Fprintf(cli.out, " %s\n", attribute)
   597  		}
   598  	}
   599  
   600  	return nil
   601  }
   602  
   603  func (cli *DockerCli) CmdStop(args ...string) error {
   604  	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period", true)
   605  	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
   606  	cmd.Require(flag.Min, 1)
   607  
   608  	utils.ParseFlags(cmd, args, true)
   609  
   610  	v := url.Values{}
   611  	v.Set("t", strconv.Itoa(*nSeconds))
   612  
   613  	var encounteredError error
   614  	for _, name := range cmd.Args() {
   615  		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false))
   616  		if err != nil {
   617  			fmt.Fprintf(cli.err, "%s\n", err)
   618  			encounteredError = fmt.Errorf("Error: failed to stop one or more containers")
   619  		} else {
   620  			fmt.Fprintf(cli.out, "%s\n", name)
   621  		}
   622  	}
   623  	return encounteredError
   624  }
   625  
   626  func (cli *DockerCli) CmdRestart(args ...string) error {
   627  	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
   628  	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
   629  	cmd.Require(flag.Min, 1)
   630  
   631  	utils.ParseFlags(cmd, args, true)
   632  
   633  	v := url.Values{}
   634  	v.Set("t", strconv.Itoa(*nSeconds))
   635  
   636  	var encounteredError error
   637  	for _, name := range cmd.Args() {
   638  		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false))
   639  		if err != nil {
   640  			fmt.Fprintf(cli.err, "%s\n", err)
   641  			encounteredError = fmt.Errorf("Error: failed to restart one or more containers")
   642  		} else {
   643  			fmt.Fprintf(cli.out, "%s\n", name)
   644  		}
   645  	}
   646  	return encounteredError
   647  }
   648  
   649  func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
   650  	sigc := make(chan os.Signal, 128)
   651  	signal.CatchAll(sigc)
   652  	go func() {
   653  		for s := range sigc {
   654  			if s == signal.SIGCHLD {
   655  				continue
   656  			}
   657  			var sig string
   658  			for sigStr, sigN := range signal.SignalMap {
   659  				if sigN == s {
   660  					sig = sigStr
   661  					break
   662  				}
   663  			}
   664  			if sig == "" {
   665  				log.Errorf("Unsupported signal: %v. Discarding.", s)
   666  			}
   667  			if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
   668  				log.Debugf("Error sending signal: %s", err)
   669  			}
   670  		}
   671  	}()
   672  	return sigc
   673  }
   674  
   675  func (cli *DockerCli) CmdStart(args ...string) error {
   676  	var (
   677  		cErr chan error
   678  		tty  bool
   679  
   680  		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container", true)
   681  		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
   682  		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
   683  	)
   684  
   685  	cmd.Require(flag.Min, 1)
   686  	utils.ParseFlags(cmd, args, true)
   687  
   688  	hijacked := make(chan io.Closer)
   689  
   690  	if *attach || *openStdin {
   691  		if cmd.NArg() > 1 {
   692  			return fmt.Errorf("You cannot start and attach multiple containers at once.")
   693  		}
   694  
   695  		stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
   696  		if err != nil {
   697  			return err
   698  		}
   699  
   700  		env := engine.Env{}
   701  		if err := env.Decode(stream); err != nil {
   702  			return err
   703  		}
   704  		config := env.GetSubEnv("Config")
   705  		tty = config.GetBool("Tty")
   706  
   707  		if !tty {
   708  			sigc := cli.forwardAllSignals(cmd.Arg(0))
   709  			defer signal.StopCatch(sigc)
   710  		}
   711  
   712  		var in io.ReadCloser
   713  
   714  		v := url.Values{}
   715  		v.Set("stream", "1")
   716  
   717  		if *openStdin && config.GetBool("OpenStdin") {
   718  			v.Set("stdin", "1")
   719  			in = cli.in
   720  		}
   721  
   722  		v.Set("stdout", "1")
   723  		v.Set("stderr", "1")
   724  
   725  		cErr = promise.Go(func() error {
   726  			return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil)
   727  		})
   728  	} else {
   729  		close(hijacked)
   730  	}
   731  
   732  	// Acknowledge the hijack before starting
   733  	select {
   734  	case closer := <-hijacked:
   735  		// Make sure that the hijack gets closed when returning (results
   736  		// in closing the hijack chan and freeing server's goroutines)
   737  		if closer != nil {
   738  			defer closer.Close()
   739  		}
   740  	case err := <-cErr:
   741  		if err != nil {
   742  			return err
   743  		}
   744  	}
   745  
   746  	var encounteredError error
   747  	for _, name := range cmd.Args() {
   748  		_, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false))
   749  		if err != nil {
   750  			if !*attach && !*openStdin {
   751  				fmt.Fprintf(cli.err, "%s\n", err)
   752  			}
   753  			encounteredError = fmt.Errorf("Error: failed to start one or more containers")
   754  		} else {
   755  			if !*attach && !*openStdin {
   756  				fmt.Fprintf(cli.out, "%s\n", name)
   757  			}
   758  		}
   759  	}
   760  	if encounteredError != nil {
   761  		if *openStdin || *attach {
   762  			cli.in.Close()
   763  		}
   764  		return encounteredError
   765  	}
   766  
   767  	if *openStdin || *attach {
   768  		if tty && cli.isTerminalOut {
   769  			if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
   770  				log.Errorf("Error monitoring TTY size: %s", err)
   771  			}
   772  		}
   773  		if attchErr := <-cErr; attchErr != nil {
   774  			return attchErr
   775  		}
   776  		_, status, err := getExitCode(cli, cmd.Arg(0))
   777  		if err != nil {
   778  			return err
   779  		}
   780  		if status != 0 {
   781  			return &utils.StatusError{StatusCode: status}
   782  		}
   783  	}
   784  	return nil
   785  }
   786  
   787  func (cli *DockerCli) CmdUnpause(args ...string) error {
   788  	cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container", true)
   789  	cmd.Require(flag.Exact, 1)
   790  	utils.ParseFlags(cmd, args, false)
   791  
   792  	var encounteredError error
   793  	for _, name := range cmd.Args() {
   794  		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/unpause", name), nil, false)); err != nil {
   795  			fmt.Fprintf(cli.err, "%s\n", err)
   796  			encounteredError = fmt.Errorf("Error: failed to unpause container named %s", name)
   797  		} else {
   798  			fmt.Fprintf(cli.out, "%s\n", name)
   799  		}
   800  	}
   801  	return encounteredError
   802  }
   803  
   804  func (cli *DockerCli) CmdPause(args ...string) error {
   805  	cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container", true)
   806  	cmd.Require(flag.Exact, 1)
   807  	utils.ParseFlags(cmd, args, false)
   808  
   809  	var encounteredError error
   810  	for _, name := range cmd.Args() {
   811  		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/pause", name), nil, false)); err != nil {
   812  			fmt.Fprintf(cli.err, "%s\n", err)
   813  			encounteredError = fmt.Errorf("Error: failed to pause container named %s", name)
   814  		} else {
   815  			fmt.Fprintf(cli.out, "%s\n", name)
   816  		}
   817  	}
   818  	return encounteredError
   819  }
   820  
   821  func (cli *DockerCli) CmdRename(args ...string) error {
   822  	cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
   823  	if err := cmd.Parse(args); err != nil {
   824  		return nil
   825  	}
   826  
   827  	if cmd.NArg() != 2 {
   828  		cmd.Usage()
   829  		return nil
   830  	}
   831  	old_name := cmd.Arg(0)
   832  	new_name := cmd.Arg(1)
   833  
   834  	if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil {
   835  		fmt.Fprintf(cli.err, "%s\n", err)
   836  		return fmt.Errorf("Error: failed to rename container named %s", old_name)
   837  	}
   838  	return nil
   839  }
   840  
   841  func (cli *DockerCli) CmdInspect(args ...string) error {
   842  	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
   843  	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
   844  	cmd.Require(flag.Min, 1)
   845  
   846  	utils.ParseFlags(cmd, args, true)
   847  
   848  	var tmpl *template.Template
   849  	if *tmplStr != "" {
   850  		var err error
   851  		if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
   852  			fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
   853  			return &utils.StatusError{StatusCode: 64,
   854  				Status: "Template parsing error: " + err.Error()}
   855  		}
   856  	}
   857  
   858  	indented := new(bytes.Buffer)
   859  	indented.WriteByte('[')
   860  	status := 0
   861  
   862  	for _, name := range cmd.Args() {
   863  		obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
   864  		if err != nil {
   865  			obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false))
   866  			if err != nil {
   867  				if strings.Contains(err.Error(), "No such") {
   868  					fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
   869  				} else {
   870  					fmt.Fprintf(cli.err, "%s", err)
   871  				}
   872  				status = 1
   873  				continue
   874  			}
   875  		}
   876  
   877  		if tmpl == nil {
   878  			if err = json.Indent(indented, obj, "", "    "); err != nil {
   879  				fmt.Fprintf(cli.err, "%s\n", err)
   880  				status = 1
   881  				continue
   882  			}
   883  		} else {
   884  			// Has template, will render
   885  			var value interface{}
   886  			if err := json.Unmarshal(obj, &value); err != nil {
   887  				fmt.Fprintf(cli.err, "%s\n", err)
   888  				status = 1
   889  				continue
   890  			}
   891  			if err := tmpl.Execute(cli.out, value); err != nil {
   892  				return err
   893  			}
   894  			cli.out.Write([]byte{'\n'})
   895  		}
   896  		indented.WriteString(",")
   897  	}
   898  
   899  	if indented.Len() > 1 {
   900  		// Remove trailing ','
   901  		indented.Truncate(indented.Len() - 1)
   902  	}
   903  	indented.WriteString("]\n")
   904  
   905  	if tmpl == nil {
   906  		if _, err := io.Copy(cli.out, indented); err != nil {
   907  			return err
   908  		}
   909  	}
   910  
   911  	if status != 0 {
   912  		return &utils.StatusError{StatusCode: status}
   913  	}
   914  	return nil
   915  }
   916  
   917  func (cli *DockerCli) CmdTop(args ...string) error {
   918  	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
   919  	cmd.Require(flag.Min, 1)
   920  
   921  	utils.ParseFlags(cmd, args, true)
   922  
   923  	val := url.Values{}
   924  	if cmd.NArg() > 1 {
   925  		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
   926  	}
   927  
   928  	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)
   929  	if err != nil {
   930  		return err
   931  	}
   932  	var procs engine.Env
   933  	if err := procs.Decode(stream); err != nil {
   934  		return err
   935  	}
   936  	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
   937  	fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t"))
   938  	processes := [][]string{}
   939  	if err := procs.GetJson("Processes", &processes); err != nil {
   940  		return err
   941  	}
   942  	for _, proc := range processes {
   943  		fmt.Fprintln(w, strings.Join(proc, "\t"))
   944  	}
   945  	w.Flush()
   946  	return nil
   947  }
   948  
   949  func (cli *DockerCli) CmdPort(args ...string) error {
   950  	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT", true)
   951  	cmd.Require(flag.Min, 1)
   952  	utils.ParseFlags(cmd, args, true)
   953  
   954  	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
   955  	if err != nil {
   956  		return err
   957  	}
   958  
   959  	env := engine.Env{}
   960  	if err := env.Decode(stream); err != nil {
   961  		return err
   962  	}
   963  	ports := nat.PortMap{}
   964  	if err := env.GetSubEnv("NetworkSettings").GetJson("Ports", &ports); err != nil {
   965  		return err
   966  	}
   967  
   968  	if cmd.NArg() == 2 {
   969  		var (
   970  			port  = cmd.Arg(1)
   971  			proto = "tcp"
   972  			parts = strings.SplitN(port, "/", 2)
   973  		)
   974  
   975  		if len(parts) == 2 && len(parts[1]) != 0 {
   976  			port = parts[0]
   977  			proto = parts[1]
   978  		}
   979  		natPort := port + "/" + proto
   980  		if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
   981  			for _, frontend := range frontends {
   982  				fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
   983  			}
   984  			return nil
   985  		}
   986  		return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
   987  	}
   988  
   989  	for from, frontends := range ports {
   990  		for _, frontend := range frontends {
   991  			fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
   992  		}
   993  	}
   994  
   995  	return nil
   996  }
   997  
   998  // 'docker rmi IMAGE' removes all images with the name IMAGE
   999  func (cli *DockerCli) CmdRmi(args ...string) error {
  1000  	var (
  1001  		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
  1002  		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
  1003  		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
  1004  	)
  1005  	cmd.Require(flag.Min, 1)
  1006  
  1007  	utils.ParseFlags(cmd, args, true)
  1008  
  1009  	v := url.Values{}
  1010  	if *force {
  1011  		v.Set("force", "1")
  1012  	}
  1013  	if *noprune {
  1014  		v.Set("noprune", "1")
  1015  	}
  1016  
  1017  	var encounteredError error
  1018  	for _, name := range cmd.Args() {
  1019  		body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, false))
  1020  		if err != nil {
  1021  			fmt.Fprintf(cli.err, "%s\n", err)
  1022  			encounteredError = fmt.Errorf("Error: failed to remove one or more images")
  1023  		} else {
  1024  			outs := engine.NewTable("Created", 0)
  1025  			if _, err := outs.ReadListFrom(body); err != nil {
  1026  				fmt.Fprintf(cli.err, "%s\n", err)
  1027  				encounteredError = fmt.Errorf("Error: failed to remove one or more images")
  1028  				continue
  1029  			}
  1030  			for _, out := range outs.Data {
  1031  				if out.Get("Deleted") != "" {
  1032  					fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted"))
  1033  				} else {
  1034  					fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged"))
  1035  				}
  1036  			}
  1037  		}
  1038  	}
  1039  	return encounteredError
  1040  }
  1041  
  1042  func (cli *DockerCli) CmdHistory(args ...string) error {
  1043  	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
  1044  	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
  1045  	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1046  	cmd.Require(flag.Exact, 1)
  1047  
  1048  	utils.ParseFlags(cmd, args, true)
  1049  
  1050  	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
  1051  	if err != nil {
  1052  		return err
  1053  	}
  1054  
  1055  	outs := engine.NewTable("Created", 0)
  1056  	if _, err := outs.ReadListFrom(body); err != nil {
  1057  		return err
  1058  	}
  1059  
  1060  	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1061  	if !*quiet {
  1062  		fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE")
  1063  	}
  1064  
  1065  	for _, out := range outs.Data {
  1066  		outID := out.Get("Id")
  1067  		if !*quiet {
  1068  			if *noTrunc {
  1069  				fmt.Fprintf(w, "%s\t", outID)
  1070  			} else {
  1071  				fmt.Fprintf(w, "%s\t", utils.TruncateID(outID))
  1072  			}
  1073  
  1074  			fmt.Fprintf(w, "%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))))
  1075  
  1076  			if *noTrunc {
  1077  				fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
  1078  			} else {
  1079  				fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45))
  1080  			}
  1081  			fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("Size"))))
  1082  		} else {
  1083  			if *noTrunc {
  1084  				fmt.Fprintln(w, outID)
  1085  			} else {
  1086  				fmt.Fprintln(w, utils.TruncateID(outID))
  1087  			}
  1088  		}
  1089  	}
  1090  	w.Flush()
  1091  	return nil
  1092  }
  1093  
  1094  func (cli *DockerCli) CmdRm(args ...string) error {
  1095  	cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
  1096  	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
  1097  	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
  1098  	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
  1099  	cmd.Require(flag.Min, 1)
  1100  
  1101  	utils.ParseFlags(cmd, args, true)
  1102  
  1103  	val := url.Values{}
  1104  	if *v {
  1105  		val.Set("v", "1")
  1106  	}
  1107  	if *link {
  1108  		val.Set("link", "1")
  1109  	}
  1110  
  1111  	if *force {
  1112  		val.Set("force", "1")
  1113  	}
  1114  
  1115  	var encounteredError error
  1116  	for _, name := range cmd.Args() {
  1117  		_, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false))
  1118  		if err != nil {
  1119  			fmt.Fprintf(cli.err, "%s\n", err)
  1120  			encounteredError = fmt.Errorf("Error: failed to remove one or more containers")
  1121  		} else {
  1122  			fmt.Fprintf(cli.out, "%s\n", name)
  1123  		}
  1124  	}
  1125  	return encounteredError
  1126  }
  1127  
  1128  // 'docker kill NAME' kills a running container
  1129  func (cli *DockerCli) CmdKill(args ...string) error {
  1130  	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
  1131  	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
  1132  	cmd.Require(flag.Min, 1)
  1133  
  1134  	utils.ParseFlags(cmd, args, true)
  1135  
  1136  	var encounteredError error
  1137  	for _, name := range cmd.Args() {
  1138  		if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, false)); err != nil {
  1139  			fmt.Fprintf(cli.err, "%s\n", err)
  1140  			encounteredError = fmt.Errorf("Error: failed to kill one or more containers")
  1141  		} else {
  1142  			fmt.Fprintf(cli.out, "%s\n", name)
  1143  		}
  1144  	}
  1145  	return encounteredError
  1146  }
  1147  
  1148  func (cli *DockerCli) CmdImport(args ...string) error {
  1149  	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.", true)
  1150  	cmd.Require(flag.Min, 1)
  1151  
  1152  	utils.ParseFlags(cmd, args, true)
  1153  
  1154  	var (
  1155  		v          = url.Values{}
  1156  		src        = cmd.Arg(0)
  1157  		repository = cmd.Arg(1)
  1158  	)
  1159  
  1160  	v.Set("fromSrc", src)
  1161  	v.Set("repo", repository)
  1162  
  1163  	if cmd.NArg() == 3 {
  1164  		fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
  1165  		v.Set("tag", cmd.Arg(2))
  1166  	}
  1167  
  1168  	if repository != "" {
  1169  		//Check if the given image name can be resolved
  1170  		repo, _ := parsers.ParseRepositoryTag(repository)
  1171  		if err := registry.ValidateRepositoryName(repo); err != nil {
  1172  			return err
  1173  		}
  1174  	}
  1175  
  1176  	var in io.Reader
  1177  
  1178  	if src == "-" {
  1179  		in = cli.in
  1180  	}
  1181  
  1182  	return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
  1183  }
  1184  
  1185  func (cli *DockerCli) CmdPush(args ...string) error {
  1186  	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
  1187  	cmd.Require(flag.Exact, 1)
  1188  
  1189  	utils.ParseFlags(cmd, args, true)
  1190  
  1191  	name := cmd.Arg(0)
  1192  
  1193  	cli.LoadConfigFile()
  1194  
  1195  	remote, tag := parsers.ParseRepositoryTag(name)
  1196  
  1197  	// Resolve the Repository name from fqn to RepositoryInfo
  1198  	repoInfo, err := registry.ParseRepositoryInfo(remote)
  1199  	if err != nil {
  1200  		return err
  1201  	}
  1202  	// Resolve the Auth config relevant for this server
  1203  	authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1204  	// If we're not using a custom registry, we know the restrictions
  1205  	// applied to repository names and can warn the user in advance.
  1206  	// Custom repositories can have different rules, and we must also
  1207  	// allow pushing by image ID.
  1208  	if repoInfo.Official {
  1209  		username := authConfig.Username
  1210  		if username == "" {
  1211  			username = "<user>"
  1212  		}
  1213  		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
  1214  	}
  1215  
  1216  	v := url.Values{}
  1217  	v.Set("tag", tag)
  1218  	push := func(authConfig registry.AuthConfig) error {
  1219  		buf, err := json.Marshal(authConfig)
  1220  		if err != nil {
  1221  			return err
  1222  		}
  1223  		registryAuthHeader := []string{
  1224  			base64.URLEncoding.EncodeToString(buf),
  1225  		}
  1226  
  1227  		return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
  1228  			"X-Registry-Auth": registryAuthHeader,
  1229  		})
  1230  	}
  1231  
  1232  	if err := push(authConfig); err != nil {
  1233  		if strings.Contains(err.Error(), "Status 401") {
  1234  			fmt.Fprintln(cli.out, "\nPlease login prior to push:")
  1235  			if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
  1236  				return err
  1237  			}
  1238  			authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1239  			return push(authConfig)
  1240  		}
  1241  		return err
  1242  	}
  1243  	return nil
  1244  }
  1245  
  1246  func (cli *DockerCli) CmdPull(args ...string) error {
  1247  	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry", true)
  1248  	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
  1249  	cmd.Require(flag.Exact, 1)
  1250  
  1251  	utils.ParseFlags(cmd, args, true)
  1252  
  1253  	var (
  1254  		v         = url.Values{}
  1255  		remote    = cmd.Arg(0)
  1256  		newRemote = remote
  1257  	)
  1258  	taglessRemote, tag := parsers.ParseRepositoryTag(remote)
  1259  	if tag == "" && !*allTags {
  1260  		newRemote = taglessRemote + ":" + graph.DEFAULTTAG
  1261  	}
  1262  	if tag != "" && *allTags {
  1263  		return fmt.Errorf("tag can't be used with --all-tags/-a")
  1264  	}
  1265  
  1266  	v.Set("fromImage", newRemote)
  1267  
  1268  	// Resolve the Repository name from fqn to RepositoryInfo
  1269  	repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
  1270  	if err != nil {
  1271  		return err
  1272  	}
  1273  
  1274  	cli.LoadConfigFile()
  1275  
  1276  	// Resolve the Auth config relevant for this server
  1277  	authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1278  
  1279  	pull := func(authConfig registry.AuthConfig) error {
  1280  		buf, err := json.Marshal(authConfig)
  1281  		if err != nil {
  1282  			return err
  1283  		}
  1284  		registryAuthHeader := []string{
  1285  			base64.URLEncoding.EncodeToString(buf),
  1286  		}
  1287  
  1288  		return cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, map[string][]string{
  1289  			"X-Registry-Auth": registryAuthHeader,
  1290  		})
  1291  	}
  1292  
  1293  	if err := pull(authConfig); err != nil {
  1294  		if strings.Contains(err.Error(), "Status 401") {
  1295  			fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
  1296  			if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
  1297  				return err
  1298  			}
  1299  			authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1300  			return pull(authConfig)
  1301  		}
  1302  		return err
  1303  	}
  1304  
  1305  	return nil
  1306  }
  1307  
  1308  func (cli *DockerCli) CmdImages(args ...string) error {
  1309  	cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
  1310  	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
  1311  	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate image layers)")
  1312  	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1313  	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1314  	flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
  1315  	flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
  1316  
  1317  	flFilter := opts.NewListOpts(nil)
  1318  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
  1319  	cmd.Require(flag.Max, 1)
  1320  
  1321  	utils.ParseFlags(cmd, args, true)
  1322  
  1323  	// Consolidate all filter flags, and sanity check them early.
  1324  	// They'll get process in the daemon/server.
  1325  	imageFilterArgs := filters.Args{}
  1326  	for _, f := range flFilter.GetAll() {
  1327  		var err error
  1328  		imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs)
  1329  		if err != nil {
  1330  			return err
  1331  		}
  1332  	}
  1333  
  1334  	for name := range imageFilterArgs {
  1335  		if _, ok := acceptedImageFilterTags[name]; !ok {
  1336  			return fmt.Errorf("Invalid filter '%s'", name)
  1337  		}
  1338  	}
  1339  
  1340  	matchName := cmd.Arg(0)
  1341  	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1342  	if *flViz || *flTree {
  1343  		v := url.Values{
  1344  			"all": []string{"1"},
  1345  		}
  1346  		if len(imageFilterArgs) > 0 {
  1347  			filterJson, err := filters.ToParam(imageFilterArgs)
  1348  			if err != nil {
  1349  				return err
  1350  			}
  1351  			v.Set("filters", filterJson)
  1352  		}
  1353  
  1354  		body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
  1355  		if err != nil {
  1356  			return err
  1357  		}
  1358  
  1359  		outs := engine.NewTable("Created", 0)
  1360  		if _, err := outs.ReadListFrom(body); err != nil {
  1361  			return err
  1362  		}
  1363  
  1364  		var (
  1365  			printNode  func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)
  1366  			startImage *engine.Env
  1367  
  1368  			roots    = engine.NewTable("Created", outs.Len())
  1369  			byParent = make(map[string]*engine.Table)
  1370  		)
  1371  
  1372  		for _, image := range outs.Data {
  1373  			if image.Get("ParentId") == "" {
  1374  				roots.Add(image)
  1375  			} else {
  1376  				if children, exists := byParent[image.Get("ParentId")]; exists {
  1377  					children.Add(image)
  1378  				} else {
  1379  					byParent[image.Get("ParentId")] = engine.NewTable("Created", 1)
  1380  					byParent[image.Get("ParentId")].Add(image)
  1381  				}
  1382  			}
  1383  
  1384  			if matchName != "" {
  1385  				if matchName == image.Get("Id") || matchName == utils.TruncateID(image.Get("Id")) {
  1386  					startImage = image
  1387  				}
  1388  
  1389  				for _, repotag := range image.GetList("RepoTags") {
  1390  					if repotag == matchName {
  1391  						startImage = image
  1392  					}
  1393  				}
  1394  			}
  1395  		}
  1396  
  1397  		if *flViz {
  1398  			fmt.Fprintf(cli.out, "digraph docker {\n")
  1399  			printNode = (*DockerCli).printVizNode
  1400  		} else {
  1401  			printNode = (*DockerCli).printTreeNode
  1402  		}
  1403  
  1404  		if startImage != nil {
  1405  			root := engine.NewTable("Created", 1)
  1406  			root.Add(startImage)
  1407  			cli.WalkTree(*noTrunc, root, byParent, "", printNode)
  1408  		} else if matchName == "" {
  1409  			cli.WalkTree(*noTrunc, roots, byParent, "", printNode)
  1410  		}
  1411  		if *flViz {
  1412  			fmt.Fprintf(cli.out, " base [style=invisible]\n}\n")
  1413  		}
  1414  	} else {
  1415  		v := url.Values{}
  1416  		if len(imageFilterArgs) > 0 {
  1417  			filterJson, err := filters.ToParam(imageFilterArgs)
  1418  			if err != nil {
  1419  				return err
  1420  			}
  1421  			v.Set("filters", filterJson)
  1422  		}
  1423  
  1424  		if cmd.NArg() == 1 {
  1425  			// FIXME rename this parameter, to not be confused with the filters flag
  1426  			v.Set("filter", matchName)
  1427  		}
  1428  		if *all {
  1429  			v.Set("all", "1")
  1430  		}
  1431  
  1432  		body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
  1433  
  1434  		if err != nil {
  1435  			return err
  1436  		}
  1437  
  1438  		outs := engine.NewTable("Created", 0)
  1439  		if _, err := outs.ReadListFrom(body); err != nil {
  1440  			return err
  1441  		}
  1442  
  1443  		w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1444  		if !*quiet {
  1445  			fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
  1446  		}
  1447  
  1448  		for _, out := range outs.Data {
  1449  			for _, repotag := range out.GetList("RepoTags") {
  1450  
  1451  				repo, tag := parsers.ParseRepositoryTag(repotag)
  1452  				outID := out.Get("Id")
  1453  				if !*noTrunc {
  1454  					outID = utils.TruncateID(outID)
  1455  				}
  1456  
  1457  				if !*quiet {
  1458  					fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), units.HumanSize(float64(out.GetInt64("VirtualSize"))))
  1459  				} else {
  1460  					fmt.Fprintln(w, outID)
  1461  				}
  1462  			}
  1463  		}
  1464  
  1465  		if !*quiet {
  1466  			w.Flush()
  1467  		}
  1468  	}
  1469  	return nil
  1470  }
  1471  
  1472  // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1473  func (cli *DockerCli) WalkTree(noTrunc bool, images *engine.Table, byParent map[string]*engine.Table, prefix string, printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)) {
  1474  	length := images.Len()
  1475  	if length > 1 {
  1476  		for index, image := range images.Data {
  1477  			if index+1 == length {
  1478  				printNode(cli, noTrunc, image, prefix+"└─")
  1479  				if subimages, exists := byParent[image.Get("Id")]; exists {
  1480  					cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
  1481  				}
  1482  			} else {
  1483  				printNode(cli, noTrunc, image, prefix+"\u251C─")
  1484  				if subimages, exists := byParent[image.Get("Id")]; exists {
  1485  					cli.WalkTree(noTrunc, subimages, byParent, prefix+"\u2502 ", printNode)
  1486  				}
  1487  			}
  1488  		}
  1489  	} else {
  1490  		for _, image := range images.Data {
  1491  			printNode(cli, noTrunc, image, prefix+"└─")
  1492  			if subimages, exists := byParent[image.Get("Id")]; exists {
  1493  				cli.WalkTree(noTrunc, subimages, byParent, prefix+"  ", printNode)
  1494  			}
  1495  		}
  1496  	}
  1497  }
  1498  
  1499  // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1500  func (cli *DockerCli) printVizNode(noTrunc bool, image *engine.Env, prefix string) {
  1501  	var (
  1502  		imageID  string
  1503  		parentID string
  1504  	)
  1505  	if noTrunc {
  1506  		imageID = image.Get("Id")
  1507  		parentID = image.Get("ParentId")
  1508  	} else {
  1509  		imageID = utils.TruncateID(image.Get("Id"))
  1510  		parentID = utils.TruncateID(image.Get("ParentId"))
  1511  	}
  1512  	if parentID == "" {
  1513  		fmt.Fprintf(cli.out, " base -> \"%s\" [style=invis]\n", imageID)
  1514  	} else {
  1515  		fmt.Fprintf(cli.out, " \"%s\" -> \"%s\"\n", parentID, imageID)
  1516  	}
  1517  	if image.GetList("RepoTags")[0] != "<none>:<none>" {
  1518  		fmt.Fprintf(cli.out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n",
  1519  			imageID, imageID, strings.Join(image.GetList("RepoTags"), "\\n"))
  1520  	}
  1521  }
  1522  
  1523  // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1524  func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix string) {
  1525  	var imageID string
  1526  	if noTrunc {
  1527  		imageID = image.Get("Id")
  1528  	} else {
  1529  		imageID = utils.TruncateID(image.Get("Id"))
  1530  	}
  1531  
  1532  	fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, units.HumanSize(float64(image.GetInt64("VirtualSize"))))
  1533  	if image.GetList("RepoTags")[0] != "<none>:<none>" {
  1534  		fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
  1535  	} else {
  1536  		fmt.Fprint(cli.out, "\n")
  1537  	}
  1538  }
  1539  
  1540  func (cli *DockerCli) CmdPs(args ...string) error {
  1541  	var (
  1542  		err error
  1543  
  1544  		psFilterArgs = filters.Args{}
  1545  		v            = url.Values{}
  1546  
  1547  		cmd      = cli.Subcmd("ps", "", "List containers", true)
  1548  		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
  1549  		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
  1550  		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
  1551  		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1552  		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
  1553  		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
  1554  		before   = cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
  1555  		last     = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
  1556  		flFilter = opts.NewListOpts(nil)
  1557  	)
  1558  	cmd.Require(flag.Exact, 0)
  1559  
  1560  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
  1561  
  1562  	utils.ParseFlags(cmd, args, true)
  1563  	if *last == -1 && *nLatest {
  1564  		*last = 1
  1565  	}
  1566  
  1567  	if *all {
  1568  		v.Set("all", "1")
  1569  	}
  1570  
  1571  	if *last != -1 {
  1572  		v.Set("limit", strconv.Itoa(*last))
  1573  	}
  1574  
  1575  	if *since != "" {
  1576  		v.Set("since", *since)
  1577  	}
  1578  
  1579  	if *before != "" {
  1580  		v.Set("before", *before)
  1581  	}
  1582  
  1583  	if *size {
  1584  		v.Set("size", "1")
  1585  	}
  1586  
  1587  	// Consolidate all filter flags, and sanity check them.
  1588  	// They'll get processed in the daemon/server.
  1589  	for _, f := range flFilter.GetAll() {
  1590  		if psFilterArgs, err = filters.ParseFlag(f, psFilterArgs); err != nil {
  1591  			return err
  1592  		}
  1593  	}
  1594  
  1595  	if len(psFilterArgs) > 0 {
  1596  		filterJson, err := filters.ToParam(psFilterArgs)
  1597  		if err != nil {
  1598  			return err
  1599  		}
  1600  
  1601  		v.Set("filters", filterJson)
  1602  	}
  1603  
  1604  	body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
  1605  	if err != nil {
  1606  		return err
  1607  	}
  1608  
  1609  	outs := engine.NewTable("Created", 0)
  1610  	if _, err := outs.ReadListFrom(body); err != nil {
  1611  		return err
  1612  	}
  1613  
  1614  	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1615  	if !*quiet {
  1616  		fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
  1617  
  1618  		if *size {
  1619  			fmt.Fprintln(w, "\tSIZE")
  1620  		} else {
  1621  			fmt.Fprint(w, "\n")
  1622  		}
  1623  	}
  1624  
  1625  	stripNamePrefix := func(ss []string) []string {
  1626  		for i, s := range ss {
  1627  			ss[i] = s[1:]
  1628  		}
  1629  
  1630  		return ss
  1631  	}
  1632  
  1633  	for _, out := range outs.Data {
  1634  		outID := out.Get("Id")
  1635  
  1636  		if !*noTrunc {
  1637  			outID = utils.TruncateID(outID)
  1638  		}
  1639  
  1640  		if *quiet {
  1641  			fmt.Fprintln(w, outID)
  1642  
  1643  			continue
  1644  		}
  1645  
  1646  		var (
  1647  			outNames   = stripNamePrefix(out.GetList("Names"))
  1648  			outCommand = strconv.Quote(out.Get("Command"))
  1649  			ports      = engine.NewTable("", 0)
  1650  		)
  1651  
  1652  		if !*noTrunc {
  1653  			outCommand = utils.Trunc(outCommand, 20)
  1654  
  1655  			// only display the default name for the container with notrunc is passed
  1656  			for _, name := range outNames {
  1657  				if len(strings.Split(name, "/")) == 1 {
  1658  					outNames = []string{name}
  1659  
  1660  					break
  1661  				}
  1662  			}
  1663  		}
  1664  
  1665  		ports.ReadListFrom([]byte(out.Get("Ports")))
  1666  
  1667  		image := out.Get("Image")
  1668  		if image == "" {
  1669  			image = "<no image>"
  1670  		}
  1671  
  1672  		fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, image, outCommand,
  1673  			units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))),
  1674  			out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
  1675  
  1676  		if *size {
  1677  			if out.GetInt("SizeRootFs") > 0 {
  1678  				fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(float64(out.GetInt64("SizeRw"))), units.HumanSize(float64(out.GetInt64("SizeRootFs"))))
  1679  			} else {
  1680  				fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("SizeRw"))))
  1681  			}
  1682  
  1683  			continue
  1684  		}
  1685  
  1686  		fmt.Fprint(w, "\n")
  1687  	}
  1688  
  1689  	if !*quiet {
  1690  		w.Flush()
  1691  	}
  1692  
  1693  	return nil
  1694  }
  1695  
  1696  func (cli *DockerCli) CmdCommit(args ...string) error {
  1697  	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
  1698  	flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
  1699  	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
  1700  	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
  1701  	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
  1702  	flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
  1703  	cmd.Require(flag.Max, 2)
  1704  	cmd.Require(flag.Min, 1)
  1705  	utils.ParseFlags(cmd, args, true)
  1706  
  1707  	var (
  1708  		name            = cmd.Arg(0)
  1709  		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
  1710  	)
  1711  
  1712  	//Check if the given image name can be resolved
  1713  	if repository != "" {
  1714  		if err := registry.ValidateRepositoryName(repository); err != nil {
  1715  			return err
  1716  		}
  1717  	}
  1718  
  1719  	v := url.Values{}
  1720  	v.Set("container", name)
  1721  	v.Set("repo", repository)
  1722  	v.Set("tag", tag)
  1723  	v.Set("comment", *flComment)
  1724  	v.Set("author", *flAuthor)
  1725  
  1726  	if *flPause != true {
  1727  		v.Set("pause", "0")
  1728  	}
  1729  
  1730  	var (
  1731  		config *runconfig.Config
  1732  		env    engine.Env
  1733  	)
  1734  	if *flConfig != "" {
  1735  		config = &runconfig.Config{}
  1736  		if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
  1737  			return err
  1738  		}
  1739  	}
  1740  	stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
  1741  	if err != nil {
  1742  		return err
  1743  	}
  1744  	if err := env.Decode(stream); err != nil {
  1745  		return err
  1746  	}
  1747  
  1748  	fmt.Fprintf(cli.out, "%s\n", env.Get("Id"))
  1749  	return nil
  1750  }
  1751  
  1752  func (cli *DockerCli) CmdEvents(args ...string) error {
  1753  	cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
  1754  	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
  1755  	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
  1756  	flFilter := opts.NewListOpts(nil)
  1757  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
  1758  	cmd.Require(flag.Exact, 0)
  1759  
  1760  	utils.ParseFlags(cmd, args, true)
  1761  
  1762  	var (
  1763  		v               = url.Values{}
  1764  		loc             = time.FixedZone(time.Now().Zone())
  1765  		eventFilterArgs = filters.Args{}
  1766  	)
  1767  
  1768  	// Consolidate all filter flags, and sanity check them early.
  1769  	// They'll get process in the daemon/server.
  1770  	for _, f := range flFilter.GetAll() {
  1771  		var err error
  1772  		eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
  1773  		if err != nil {
  1774  			return err
  1775  		}
  1776  	}
  1777  	var setTime = func(key, value string) {
  1778  		format := timeutils.RFC3339NanoFixed
  1779  		if len(value) < len(format) {
  1780  			format = format[:len(value)]
  1781  		}
  1782  		if t, err := time.ParseInLocation(format, value, loc); err == nil {
  1783  			v.Set(key, strconv.FormatInt(t.Unix(), 10))
  1784  		} else {
  1785  			v.Set(key, value)
  1786  		}
  1787  	}
  1788  	if *since != "" {
  1789  		setTime("since", *since)
  1790  	}
  1791  	if *until != "" {
  1792  		setTime("until", *until)
  1793  	}
  1794  	if len(eventFilterArgs) > 0 {
  1795  		filterJson, err := filters.ToParam(eventFilterArgs)
  1796  		if err != nil {
  1797  			return err
  1798  		}
  1799  		v.Set("filters", filterJson)
  1800  	}
  1801  	if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
  1802  		return err
  1803  	}
  1804  	return nil
  1805  }
  1806  
  1807  func (cli *DockerCli) CmdExport(args ...string) error {
  1808  	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true)
  1809  	cmd.Require(flag.Exact, 1)
  1810  
  1811  	utils.ParseFlags(cmd, args, true)
  1812  
  1813  	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
  1814  		return err
  1815  	}
  1816  	return nil
  1817  }
  1818  
  1819  func (cli *DockerCli) CmdDiff(args ...string) error {
  1820  	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
  1821  	cmd.Require(flag.Exact, 1)
  1822  
  1823  	utils.ParseFlags(cmd, args, true)
  1824  
  1825  	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
  1826  
  1827  	if err != nil {
  1828  		return err
  1829  	}
  1830  
  1831  	outs := engine.NewTable("", 0)
  1832  	if _, err := outs.ReadListFrom(body); err != nil {
  1833  		return err
  1834  	}
  1835  	for _, change := range outs.Data {
  1836  		var kind string
  1837  		switch change.GetInt("Kind") {
  1838  		case archive.ChangeModify:
  1839  			kind = "C"
  1840  		case archive.ChangeAdd:
  1841  			kind = "A"
  1842  		case archive.ChangeDelete:
  1843  			kind = "D"
  1844  		}
  1845  		fmt.Fprintf(cli.out, "%s %s\n", kind, change.Get("Path"))
  1846  	}
  1847  	return nil
  1848  }
  1849  
  1850  func (cli *DockerCli) CmdLogs(args ...string) error {
  1851  	var (
  1852  		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
  1853  		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
  1854  		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
  1855  		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
  1856  	)
  1857  	cmd.Require(flag.Exact, 1)
  1858  
  1859  	utils.ParseFlags(cmd, args, true)
  1860  
  1861  	name := cmd.Arg(0)
  1862  
  1863  	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
  1864  	if err != nil {
  1865  		return err
  1866  	}
  1867  
  1868  	env := engine.Env{}
  1869  	if err := env.Decode(stream); err != nil {
  1870  		return err
  1871  	}
  1872  
  1873  	v := url.Values{}
  1874  	v.Set("stdout", "1")
  1875  	v.Set("stderr", "1")
  1876  
  1877  	if *times {
  1878  		v.Set("timestamps", "1")
  1879  	}
  1880  
  1881  	if *follow {
  1882  		v.Set("follow", "1")
  1883  	}
  1884  	v.Set("tail", *tail)
  1885  
  1886  	return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil)
  1887  }
  1888  
  1889  func (cli *DockerCli) CmdAttach(args ...string) error {
  1890  	var (
  1891  		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
  1892  		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
  1893  		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
  1894  	)
  1895  	cmd.Require(flag.Exact, 1)
  1896  
  1897  	utils.ParseFlags(cmd, args, true)
  1898  	name := cmd.Arg(0)
  1899  
  1900  	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
  1901  	if err != nil {
  1902  		return err
  1903  	}
  1904  
  1905  	env := engine.Env{}
  1906  	if err := env.Decode(stream); err != nil {
  1907  		return err
  1908  	}
  1909  
  1910  	if !env.GetSubEnv("State").GetBool("Running") {
  1911  		return fmt.Errorf("You cannot attach to a stopped container, start it first")
  1912  	}
  1913  
  1914  	var (
  1915  		config = env.GetSubEnv("Config")
  1916  		tty    = config.GetBool("Tty")
  1917  	)
  1918  
  1919  	if err := cli.CheckTtyInput(!*noStdin, tty); err != nil {
  1920  		return err
  1921  	}
  1922  
  1923  	if tty && cli.isTerminalOut {
  1924  		if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
  1925  			log.Debugf("Error monitoring TTY size: %s", err)
  1926  		}
  1927  	}
  1928  
  1929  	var in io.ReadCloser
  1930  
  1931  	v := url.Values{}
  1932  	v.Set("stream", "1")
  1933  	if !*noStdin && config.GetBool("OpenStdin") {
  1934  		v.Set("stdin", "1")
  1935  		in = cli.in
  1936  	}
  1937  
  1938  	v.Set("stdout", "1")
  1939  	v.Set("stderr", "1")
  1940  
  1941  	if *proxy && !tty {
  1942  		sigc := cli.forwardAllSignals(cmd.Arg(0))
  1943  		defer signal.StopCatch(sigc)
  1944  	}
  1945  
  1946  	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, nil, nil); err != nil {
  1947  		return err
  1948  	}
  1949  
  1950  	_, status, err := getExitCode(cli, cmd.Arg(0))
  1951  	if err != nil {
  1952  		return err
  1953  	}
  1954  	if status != 0 {
  1955  		return &utils.StatusError{StatusCode: status}
  1956  	}
  1957  
  1958  	return nil
  1959  }
  1960  
  1961  func (cli *DockerCli) CmdSearch(args ...string) error {
  1962  	cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
  1963  	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1964  	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
  1965  	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
  1966  	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
  1967  	cmd.Require(flag.Exact, 1)
  1968  
  1969  	utils.ParseFlags(cmd, args, true)
  1970  
  1971  	v := url.Values{}
  1972  	v.Set("term", cmd.Arg(0))
  1973  
  1974  	body, _, err := readBody(cli.call("GET", "/images/search?"+v.Encode(), nil, true))
  1975  
  1976  	if err != nil {
  1977  		return err
  1978  	}
  1979  	outs := engine.NewTable("star_count", 0)
  1980  	if _, err := outs.ReadListFrom(body); err != nil {
  1981  		return err
  1982  	}
  1983  	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
  1984  	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
  1985  	for _, out := range outs.Data {
  1986  		if ((*automated || *trusted) && (!out.GetBool("is_trusted") && !out.GetBool("is_automated"))) || (*stars > out.GetInt("star_count")) {
  1987  			continue
  1988  		}
  1989  		desc := strings.Replace(out.Get("description"), "\n", " ", -1)
  1990  		desc = strings.Replace(desc, "\r", " ", -1)
  1991  		if !*noTrunc && len(desc) > 45 {
  1992  			desc = utils.Trunc(desc, 42) + "..."
  1993  		}
  1994  		fmt.Fprintf(w, "%s\t%s\t%d\t", out.Get("name"), desc, out.GetInt("star_count"))
  1995  		if out.GetBool("is_official") {
  1996  			fmt.Fprint(w, "[OK]")
  1997  
  1998  		}
  1999  		fmt.Fprint(w, "\t")
  2000  		if out.GetBool("is_automated") || out.GetBool("is_trusted") {
  2001  			fmt.Fprint(w, "[OK]")
  2002  		}
  2003  		fmt.Fprint(w, "\n")
  2004  	}
  2005  	w.Flush()
  2006  	return nil
  2007  }
  2008  
  2009  // Ports type - Used to parse multiple -p flags
  2010  type ports []int
  2011  
  2012  func (cli *DockerCli) CmdTag(args ...string) error {
  2013  	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
  2014  	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
  2015  	cmd.Require(flag.Exact, 2)
  2016  
  2017  	utils.ParseFlags(cmd, args, true)
  2018  
  2019  	var (
  2020  		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
  2021  		v               = url.Values{}
  2022  	)
  2023  
  2024  	//Check if the given image name can be resolved
  2025  	if err := registry.ValidateRepositoryName(repository); err != nil {
  2026  		return err
  2027  	}
  2028  	v.Set("repo", repository)
  2029  	v.Set("tag", tag)
  2030  
  2031  	if *force {
  2032  		v.Set("force", "1")
  2033  	}
  2034  
  2035  	if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil {
  2036  		return err
  2037  	}
  2038  	return nil
  2039  }
  2040  
  2041  func (cli *DockerCli) pullImage(image string) error {
  2042  	return cli.pullImageCustomOut(image, cli.out)
  2043  }
  2044  
  2045  func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
  2046  	v := url.Values{}
  2047  	repos, tag := parsers.ParseRepositoryTag(image)
  2048  	// pull only the image tagged 'latest' if no tag was specified
  2049  	if tag == "" {
  2050  		tag = graph.DEFAULTTAG
  2051  	}
  2052  	v.Set("fromImage", repos)
  2053  	v.Set("tag", tag)
  2054  
  2055  	// Resolve the Repository name from fqn to RepositoryInfo
  2056  	repoInfo, err := registry.ParseRepositoryInfo(repos)
  2057  	if err != nil {
  2058  		return err
  2059  	}
  2060  
  2061  	// Load the auth config file, to be able to pull the image
  2062  	cli.LoadConfigFile()
  2063  
  2064  	// Resolve the Auth config relevant for this server
  2065  	authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  2066  	buf, err := json.Marshal(authConfig)
  2067  	if err != nil {
  2068  		return err
  2069  	}
  2070  
  2071  	registryAuthHeader := []string{
  2072  		base64.URLEncoding.EncodeToString(buf),
  2073  	}
  2074  	if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, out, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
  2075  		return err
  2076  	}
  2077  	return nil
  2078  }
  2079  
  2080  type cidFile struct {
  2081  	path    string
  2082  	file    *os.File
  2083  	written bool
  2084  }
  2085  
  2086  func newCIDFile(path string) (*cidFile, error) {
  2087  	if _, err := os.Stat(path); err == nil {
  2088  		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
  2089  	}
  2090  
  2091  	f, err := os.Create(path)
  2092  	if err != nil {
  2093  		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
  2094  	}
  2095  
  2096  	return &cidFile{path: path, file: f}, nil
  2097  }
  2098  
  2099  func (cid *cidFile) Close() error {
  2100  	cid.file.Close()
  2101  
  2102  	if !cid.written {
  2103  		if err := os.Remove(cid.path); err != nil {
  2104  			return fmt.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
  2105  		}
  2106  	}
  2107  
  2108  	return nil
  2109  }
  2110  
  2111  func (cid *cidFile) Write(id string) error {
  2112  	if _, err := cid.file.Write([]byte(id)); err != nil {
  2113  		return fmt.Errorf("Failed to write the container ID to the file: %s", err)
  2114  	}
  2115  	cid.written = true
  2116  	return nil
  2117  }
  2118  
  2119  func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (engine.Env, error) {
  2120  	containerValues := url.Values{}
  2121  	if name != "" {
  2122  		containerValues.Set("name", name)
  2123  	}
  2124  
  2125  	mergedConfig := runconfig.MergeConfigs(config, hostConfig)
  2126  
  2127  	var containerIDFile *cidFile
  2128  	if cidfile != "" {
  2129  		var err error
  2130  		if containerIDFile, err = newCIDFile(cidfile); err != nil {
  2131  			return nil, err
  2132  		}
  2133  		defer containerIDFile.Close()
  2134  	}
  2135  
  2136  	//create the container
  2137  	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false)
  2138  	//if image not found try to pull it
  2139  	if statusCode == 404 {
  2140  		repo, tag := parsers.ParseRepositoryTag(config.Image)
  2141  		if tag == "" {
  2142  			tag = graph.DEFAULTTAG
  2143  		}
  2144  		fmt.Fprintf(cli.err, "Unable to find image '%s:%s' locally\n", repo, tag)
  2145  
  2146  		// we don't want to write to stdout anything apart from container.ID
  2147  		if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
  2148  			return nil, err
  2149  		}
  2150  		// Retry
  2151  		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil {
  2152  			return nil, err
  2153  		}
  2154  	} else if err != nil {
  2155  		return nil, err
  2156  	}
  2157  
  2158  	var result engine.Env
  2159  	if err := result.Decode(stream); err != nil {
  2160  		return nil, err
  2161  	}
  2162  
  2163  	for _, warning := range result.GetList("Warnings") {
  2164  		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
  2165  	}
  2166  
  2167  	if containerIDFile != nil {
  2168  		if err = containerIDFile.Write(result.Get("Id")); err != nil {
  2169  			return nil, err
  2170  		}
  2171  	}
  2172  
  2173  	return result, nil
  2174  
  2175  }
  2176  
  2177  func (cli *DockerCli) CmdCreate(args ...string) error {
  2178  	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
  2179  
  2180  	// These are flags not stored in Config/HostConfig
  2181  	var (
  2182  		flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
  2183  	)
  2184  
  2185  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  2186  	if err != nil {
  2187  		utils.ReportError(cmd, err.Error(), true)
  2188  	}
  2189  	if config.Image == "" {
  2190  		cmd.Usage()
  2191  		return nil
  2192  	}
  2193  
  2194  	createResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  2195  	if err != nil {
  2196  		return err
  2197  	}
  2198  
  2199  	fmt.Fprintf(cli.out, "%s\n", createResult.Get("Id"))
  2200  
  2201  	return nil
  2202  }
  2203  
  2204  func (cli *DockerCli) CmdRun(args ...string) error {
  2205  	// FIXME: just use runconfig.Parse already
  2206  	cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
  2207  
  2208  	// These are flags not stored in Config/HostConfig
  2209  	var (
  2210  		flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
  2211  		flDetach     = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run the container in the background and print the new container ID")
  2212  		flSigProxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.")
  2213  		flName       = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
  2214  		flAttach     *opts.ListOpts
  2215  
  2216  		ErrConflictAttachDetach               = fmt.Errorf("Conflicting options: -a and -d")
  2217  		ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
  2218  		ErrConflictDetachAutoRemove           = fmt.Errorf("Conflicting options: --rm and -d")
  2219  	)
  2220  
  2221  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  2222  	// just in case the Parse does not exit
  2223  	if err != nil {
  2224  		utils.ReportError(cmd, err.Error(), true)
  2225  	}
  2226  	if config.Image == "" {
  2227  		cmd.Usage()
  2228  		return nil
  2229  	}
  2230  
  2231  	if !*flDetach {
  2232  		if err := cli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil {
  2233  			return err
  2234  		}
  2235  	} else {
  2236  		if fl := cmd.Lookup("attach"); fl != nil {
  2237  			flAttach = fl.Value.(*opts.ListOpts)
  2238  			if flAttach.Len() != 0 {
  2239  				return ErrConflictAttachDetach
  2240  			}
  2241  		}
  2242  		if *flAutoRemove {
  2243  			return ErrConflictDetachAutoRemove
  2244  		}
  2245  
  2246  		config.AttachStdin = false
  2247  		config.AttachStdout = false
  2248  		config.AttachStderr = false
  2249  		config.StdinOnce = false
  2250  	}
  2251  
  2252  	// Disable flSigProxy when in TTY mode
  2253  	sigProxy := *flSigProxy
  2254  	if config.Tty {
  2255  		sigProxy = false
  2256  	}
  2257  
  2258  	runResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  2259  	if err != nil {
  2260  		return err
  2261  	}
  2262  
  2263  	if sigProxy {
  2264  		sigc := cli.forwardAllSignals(runResult.Get("Id"))
  2265  		defer signal.StopCatch(sigc)
  2266  	}
  2267  
  2268  	var (
  2269  		waitDisplayId chan struct{}
  2270  		errCh         chan error
  2271  	)
  2272  
  2273  	if !config.AttachStdout && !config.AttachStderr {
  2274  		// Make this asynchronous to allow the client to write to stdin before having to read the ID
  2275  		waitDisplayId = make(chan struct{})
  2276  		go func() {
  2277  			defer close(waitDisplayId)
  2278  			fmt.Fprintf(cli.out, "%s\n", runResult.Get("Id"))
  2279  		}()
  2280  	}
  2281  
  2282  	if *flAutoRemove && (hostConfig.RestartPolicy.Name == "always" || hostConfig.RestartPolicy.Name == "on-failure") {
  2283  		return ErrConflictRestartPolicyAndAutoRemove
  2284  	}
  2285  
  2286  	// We need to instantiate the chan because the select needs it. It can
  2287  	// be closed but can't be uninitialized.
  2288  	hijacked := make(chan io.Closer)
  2289  
  2290  	// Block the return until the chan gets closed
  2291  	defer func() {
  2292  		log.Debugf("End of CmdRun(), Waiting for hijack to finish.")
  2293  		if _, ok := <-hijacked; ok {
  2294  			log.Errorf("Hijack did not finish (chan still open)")
  2295  		}
  2296  	}()
  2297  
  2298  	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
  2299  		var (
  2300  			out, stderr io.Writer
  2301  			in          io.ReadCloser
  2302  			v           = url.Values{}
  2303  		)
  2304  		v.Set("stream", "1")
  2305  
  2306  		if config.AttachStdin {
  2307  			v.Set("stdin", "1")
  2308  			in = cli.in
  2309  		}
  2310  		if config.AttachStdout {
  2311  			v.Set("stdout", "1")
  2312  			out = cli.out
  2313  		}
  2314  		if config.AttachStderr {
  2315  			v.Set("stderr", "1")
  2316  			if config.Tty {
  2317  				stderr = cli.out
  2318  			} else {
  2319  				stderr = cli.err
  2320  			}
  2321  		}
  2322  
  2323  		errCh = promise.Go(func() error {
  2324  			return cli.hijack("POST", "/containers/"+runResult.Get("Id")+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked, nil)
  2325  		})
  2326  	} else {
  2327  		close(hijacked)
  2328  	}
  2329  
  2330  	// Acknowledge the hijack before starting
  2331  	select {
  2332  	case closer := <-hijacked:
  2333  		// Make sure that the hijack gets closed when returning (results
  2334  		// in closing the hijack chan and freeing server's goroutines)
  2335  		if closer != nil {
  2336  			defer closer.Close()
  2337  		}
  2338  	case err := <-errCh:
  2339  		if err != nil {
  2340  			log.Debugf("Error hijack: %s", err)
  2341  			return err
  2342  		}
  2343  	}
  2344  
  2345  	//start the container
  2346  	if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/start", nil, false)); err != nil {
  2347  		return err
  2348  	}
  2349  
  2350  	if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminalOut {
  2351  		if err := cli.monitorTtySize(runResult.Get("Id"), false); err != nil {
  2352  			log.Errorf("Error monitoring TTY size: %s", err)
  2353  		}
  2354  	}
  2355  
  2356  	if errCh != nil {
  2357  		if err := <-errCh; err != nil {
  2358  			log.Debugf("Error hijack: %s", err)
  2359  			return err
  2360  		}
  2361  	}
  2362  
  2363  	// Detached mode: wait for the id to be displayed and return.
  2364  	if !config.AttachStdout && !config.AttachStderr {
  2365  		// Detached mode
  2366  		<-waitDisplayId
  2367  		return nil
  2368  	}
  2369  
  2370  	var status int
  2371  
  2372  	// Attached mode
  2373  	if *flAutoRemove {
  2374  		// Autoremove: wait for the container to finish, retrieve
  2375  		// the exit code and remove the container
  2376  		if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil {
  2377  			return err
  2378  		}
  2379  		if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
  2380  			return err
  2381  		}
  2382  		if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.Get("Id")+"?v=1", nil, false)); err != nil {
  2383  			return err
  2384  		}
  2385  	} else {
  2386  		// No Autoremove: Simply retrieve the exit code
  2387  		if !config.Tty {
  2388  			// In non-TTY mode, we can't detach, so we must wait for container exit
  2389  			if status, err = waitForExit(cli, runResult.Get("Id")); err != nil {
  2390  				return err
  2391  			}
  2392  		} else {
  2393  			// In TTY mode, there is a race: if the process dies too slowly, the state could
  2394  			// be updated after the getExitCode call and result in the wrong exit code being reported
  2395  			if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
  2396  				return err
  2397  			}
  2398  		}
  2399  	}
  2400  	if status != 0 {
  2401  		return &utils.StatusError{StatusCode: status}
  2402  	}
  2403  	return nil
  2404  }
  2405  
  2406  func (cli *DockerCli) CmdCp(args ...string) error {
  2407  	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH", true)
  2408  	cmd.Require(flag.Exact, 2)
  2409  
  2410  	utils.ParseFlags(cmd, args, true)
  2411  
  2412  	var copyData engine.Env
  2413  	info := strings.Split(cmd.Arg(0), ":")
  2414  
  2415  	if len(info) != 2 {
  2416  		return fmt.Errorf("Error: Path not specified")
  2417  	}
  2418  
  2419  	copyData.Set("Resource", info[1])
  2420  	copyData.Set("HostPath", cmd.Arg(1))
  2421  
  2422  	stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false)
  2423  	if stream != nil {
  2424  		defer stream.Close()
  2425  	}
  2426  	if statusCode == 404 {
  2427  		return fmt.Errorf("No such container: %v", info[0])
  2428  	}
  2429  	if err != nil {
  2430  		return err
  2431  	}
  2432  
  2433  	if statusCode == 200 {
  2434  		if err := archive.Untar(stream, copyData.Get("HostPath"), &archive.TarOptions{NoLchown: true}); err != nil {
  2435  			return err
  2436  		}
  2437  	}
  2438  	return nil
  2439  }
  2440  
  2441  func (cli *DockerCli) CmdSave(args ...string) error {
  2442  	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
  2443  	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
  2444  	cmd.Require(flag.Min, 1)
  2445  
  2446  	utils.ParseFlags(cmd, args, true)
  2447  
  2448  	var (
  2449  		output io.Writer = cli.out
  2450  		err    error
  2451  	)
  2452  	if *outfile != "" {
  2453  		output, err = os.Create(*outfile)
  2454  		if err != nil {
  2455  			return err
  2456  		}
  2457  	} else if cli.isTerminalOut {
  2458  		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
  2459  	}
  2460  
  2461  	if len(cmd.Args()) == 1 {
  2462  		image := cmd.Arg(0)
  2463  		if err := cli.stream("GET", "/images/"+image+"/get", nil, output, nil); err != nil {
  2464  			return err
  2465  		}
  2466  	} else {
  2467  		v := url.Values{}
  2468  		for _, arg := range cmd.Args() {
  2469  			v.Add("names", arg)
  2470  		}
  2471  		if err := cli.stream("GET", "/images/get?"+v.Encode(), nil, output, nil); err != nil {
  2472  			return err
  2473  		}
  2474  	}
  2475  	return nil
  2476  }
  2477  
  2478  func (cli *DockerCli) CmdLoad(args ...string) error {
  2479  	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
  2480  	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
  2481  	cmd.Require(flag.Exact, 0)
  2482  
  2483  	utils.ParseFlags(cmd, args, true)
  2484  
  2485  	var (
  2486  		input io.Reader = cli.in
  2487  		err   error
  2488  	)
  2489  	if *infile != "" {
  2490  		input, err = os.Open(*infile)
  2491  		if err != nil {
  2492  			return err
  2493  		}
  2494  	}
  2495  	if err := cli.stream("POST", "/images/load", input, cli.out, nil); err != nil {
  2496  		return err
  2497  	}
  2498  	return nil
  2499  }
  2500  
  2501  func (cli *DockerCli) CmdExec(args ...string) error {
  2502  	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
  2503  
  2504  	execConfig, err := runconfig.ParseExec(cmd, args)
  2505  	// just in case the ParseExec does not exit
  2506  	if execConfig.Container == "" || err != nil {
  2507  		return &utils.StatusError{StatusCode: 1}
  2508  	}
  2509  
  2510  	stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)
  2511  	if err != nil {
  2512  		return err
  2513  	}
  2514  
  2515  	var execResult engine.Env
  2516  	if err := execResult.Decode(stream); err != nil {
  2517  		return err
  2518  	}
  2519  
  2520  	execID := execResult.Get("Id")
  2521  
  2522  	if execID == "" {
  2523  		fmt.Fprintf(cli.out, "exec ID empty")
  2524  		return nil
  2525  	}
  2526  
  2527  	if !execConfig.Detach {
  2528  		if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
  2529  			return err
  2530  		}
  2531  	} else {
  2532  		if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, false)); err != nil {
  2533  			return err
  2534  		}
  2535  		// For now don't print this - wait for when we support exec wait()
  2536  		// fmt.Fprintf(cli.out, "%s\n", execID)
  2537  		return nil
  2538  	}
  2539  
  2540  	// Interactive exec requested.
  2541  	var (
  2542  		out, stderr io.Writer
  2543  		in          io.ReadCloser
  2544  		hijacked    = make(chan io.Closer)
  2545  		errCh       chan error
  2546  	)
  2547  
  2548  	// Block the return until the chan gets closed
  2549  	defer func() {
  2550  		log.Debugf("End of CmdExec(), Waiting for hijack to finish.")
  2551  		if _, ok := <-hijacked; ok {
  2552  			log.Errorf("Hijack did not finish (chan still open)")
  2553  		}
  2554  	}()
  2555  
  2556  	if execConfig.AttachStdin {
  2557  		in = cli.in
  2558  	}
  2559  	if execConfig.AttachStdout {
  2560  		out = cli.out
  2561  	}
  2562  	if execConfig.AttachStderr {
  2563  		if execConfig.Tty {
  2564  			stderr = cli.out
  2565  		} else {
  2566  			stderr = cli.err
  2567  		}
  2568  	}
  2569  	errCh = promise.Go(func() error {
  2570  		return cli.hijack("POST", "/exec/"+execID+"/start", execConfig.Tty, in, out, stderr, hijacked, execConfig)
  2571  	})
  2572  
  2573  	// Acknowledge the hijack before starting
  2574  	select {
  2575  	case closer := <-hijacked:
  2576  		// Make sure that hijack gets closed when returning. (result
  2577  		// in closing hijack chan and freeing server's goroutines.
  2578  		if closer != nil {
  2579  			defer closer.Close()
  2580  		}
  2581  	case err := <-errCh:
  2582  		if err != nil {
  2583  			log.Debugf("Error hijack: %s", err)
  2584  			return err
  2585  		}
  2586  	}
  2587  
  2588  	if execConfig.Tty && cli.isTerminalIn {
  2589  		if err := cli.monitorTtySize(execID, true); err != nil {
  2590  			log.Errorf("Error monitoring TTY size: %s", err)
  2591  		}
  2592  	}
  2593  
  2594  	if err := <-errCh; err != nil {
  2595  		log.Debugf("Error hijack: %s", err)
  2596  		return err
  2597  	}
  2598  
  2599  	var status int
  2600  	if _, status, err = getExecExitCode(cli, execID); err != nil {
  2601  		return err
  2602  	}
  2603  
  2604  	if status != 0 {
  2605  		return &utils.StatusError{StatusCode: status}
  2606  	}
  2607  
  2608  	return nil
  2609  }