github.com/carlanton/docker@v1.8.0-rc1/integration-cli/docker_cli_cp_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/go-check/check"
    14  )
    15  
    16  const (
    17  	cpTestPathParent = "/some"
    18  	cpTestPath       = "/some/path"
    19  	cpTestName       = "test"
    20  	cpFullPath       = "/some/path/test"
    21  
    22  	cpContainerContents = "holla, i am the container"
    23  	cpHostContents      = "hello, i am the host"
    24  )
    25  
    26  // Ensure that an all-local path case returns an error.
    27  func (s *DockerSuite) TestCpLocalOnly(c *check.C) {
    28  	err := runDockerCp(c, "foo", "bar")
    29  	if err == nil {
    30  		c.Fatal("expected failure, got success")
    31  	}
    32  
    33  	if !strings.Contains(err.Error(), "must specify at least one container source") {
    34  		c.Fatalf("unexpected output: %s", err.Error())
    35  	}
    36  }
    37  
    38  // Test for #5656
    39  // Check that garbage paths don't escape the container's rootfs
    40  func (s *DockerSuite) TestCpGarbagePath(c *check.C) {
    41  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
    42  	if exitCode != 0 {
    43  		c.Fatal("failed to create a container", out)
    44  	}
    45  
    46  	cleanedContainerID := strings.TrimSpace(out)
    47  
    48  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
    49  	if strings.TrimSpace(out) != "0" {
    50  		c.Fatal("failed to set up container", out)
    51  	}
    52  
    53  	if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
    54  		c.Fatal(err)
    55  	}
    56  
    57  	hostFile, err := os.Create(cpFullPath)
    58  	if err != nil {
    59  		c.Fatal(err)
    60  	}
    61  	defer hostFile.Close()
    62  	defer os.RemoveAll(cpTestPathParent)
    63  
    64  	fmt.Fprintf(hostFile, "%s", cpHostContents)
    65  
    66  	tmpdir, err := ioutil.TempDir("", "docker-integration")
    67  	if err != nil {
    68  		c.Fatal(err)
    69  	}
    70  
    71  	tmpname := filepath.Join(tmpdir, cpTestName)
    72  	defer os.RemoveAll(tmpdir)
    73  
    74  	path := path.Join("../../../../../../../../../../../../", cpFullPath)
    75  
    76  	dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
    77  
    78  	file, _ := os.Open(tmpname)
    79  	defer file.Close()
    80  
    81  	test, err := ioutil.ReadAll(file)
    82  	if err != nil {
    83  		c.Fatal(err)
    84  	}
    85  
    86  	if string(test) == cpHostContents {
    87  		c.Errorf("output matched host file -- garbage path can escape container rootfs")
    88  	}
    89  
    90  	if string(test) != cpContainerContents {
    91  		c.Errorf("output doesn't match the input for garbage path")
    92  	}
    93  
    94  }
    95  
    96  // Check that relative paths are relative to the container's rootfs
    97  func (s *DockerSuite) TestCpRelativePath(c *check.C) {
    98  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
    99  	if exitCode != 0 {
   100  		c.Fatal("failed to create a container", out)
   101  	}
   102  
   103  	cleanedContainerID := strings.TrimSpace(out)
   104  
   105  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   106  	if strings.TrimSpace(out) != "0" {
   107  		c.Fatal("failed to set up container", out)
   108  	}
   109  
   110  	if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
   111  		c.Fatal(err)
   112  	}
   113  
   114  	hostFile, err := os.Create(cpFullPath)
   115  	if err != nil {
   116  		c.Fatal(err)
   117  	}
   118  	defer hostFile.Close()
   119  	defer os.RemoveAll(cpTestPathParent)
   120  
   121  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   122  
   123  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   124  
   125  	if err != nil {
   126  		c.Fatal(err)
   127  	}
   128  
   129  	tmpname := filepath.Join(tmpdir, cpTestName)
   130  	defer os.RemoveAll(tmpdir)
   131  
   132  	var relPath string
   133  	if path.IsAbs(cpFullPath) {
   134  		// normally this is `filepath.Rel("/", cpFullPath)` but we cannot
   135  		// get this unix-path manipulation on windows with filepath.
   136  		relPath = cpFullPath[1:]
   137  	} else {
   138  		c.Fatalf("path %s was assumed to be an absolute path", cpFullPath)
   139  	}
   140  
   141  	dockerCmd(c, "cp", cleanedContainerID+":"+relPath, tmpdir)
   142  
   143  	file, _ := os.Open(tmpname)
   144  	defer file.Close()
   145  
   146  	test, err := ioutil.ReadAll(file)
   147  	if err != nil {
   148  		c.Fatal(err)
   149  	}
   150  
   151  	if string(test) == cpHostContents {
   152  		c.Errorf("output matched host file -- relative path can escape container rootfs")
   153  	}
   154  
   155  	if string(test) != cpContainerContents {
   156  		c.Errorf("output doesn't match the input for relative path")
   157  	}
   158  
   159  }
   160  
   161  // Check that absolute paths are relative to the container's rootfs
   162  func (s *DockerSuite) TestCpAbsolutePath(c *check.C) {
   163  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
   164  	if exitCode != 0 {
   165  		c.Fatal("failed to create a container", out)
   166  	}
   167  
   168  	cleanedContainerID := strings.TrimSpace(out)
   169  
   170  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   171  	if strings.TrimSpace(out) != "0" {
   172  		c.Fatal("failed to set up container", out)
   173  	}
   174  
   175  	if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
   176  		c.Fatal(err)
   177  	}
   178  
   179  	hostFile, err := os.Create(cpFullPath)
   180  	if err != nil {
   181  		c.Fatal(err)
   182  	}
   183  	defer hostFile.Close()
   184  	defer os.RemoveAll(cpTestPathParent)
   185  
   186  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   187  
   188  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   189  
   190  	if err != nil {
   191  		c.Fatal(err)
   192  	}
   193  
   194  	tmpname := filepath.Join(tmpdir, cpTestName)
   195  	defer os.RemoveAll(tmpdir)
   196  
   197  	path := cpFullPath
   198  
   199  	dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
   200  
   201  	file, _ := os.Open(tmpname)
   202  	defer file.Close()
   203  
   204  	test, err := ioutil.ReadAll(file)
   205  	if err != nil {
   206  		c.Fatal(err)
   207  	}
   208  
   209  	if string(test) == cpHostContents {
   210  		c.Errorf("output matched host file -- absolute path can escape container rootfs")
   211  	}
   212  
   213  	if string(test) != cpContainerContents {
   214  		c.Errorf("output doesn't match the input for absolute path")
   215  	}
   216  
   217  }
   218  
   219  // Test for #5619
   220  // Check that absolute symlinks are still relative to the container's rootfs
   221  func (s *DockerSuite) TestCpAbsoluteSymlink(c *check.C) {
   222  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path")
   223  	if exitCode != 0 {
   224  		c.Fatal("failed to create a container", out)
   225  	}
   226  
   227  	cleanedContainerID := strings.TrimSpace(out)
   228  
   229  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   230  	if strings.TrimSpace(out) != "0" {
   231  		c.Fatal("failed to set up container", out)
   232  	}
   233  
   234  	if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
   235  		c.Fatal(err)
   236  	}
   237  
   238  	hostFile, err := os.Create(cpFullPath)
   239  	if err != nil {
   240  		c.Fatal(err)
   241  	}
   242  	defer hostFile.Close()
   243  	defer os.RemoveAll(cpTestPathParent)
   244  
   245  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   246  
   247  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   248  
   249  	if err != nil {
   250  		c.Fatal(err)
   251  	}
   252  
   253  	tmpname := filepath.Join(tmpdir, cpTestName)
   254  	defer os.RemoveAll(tmpdir)
   255  
   256  	path := path.Join("/", "container_path")
   257  
   258  	dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
   259  
   260  	file, _ := os.Open(tmpname)
   261  	defer file.Close()
   262  
   263  	test, err := ioutil.ReadAll(file)
   264  	if err != nil {
   265  		c.Fatal(err)
   266  	}
   267  
   268  	if string(test) == cpHostContents {
   269  		c.Errorf("output matched host file -- absolute symlink can escape container rootfs")
   270  	}
   271  
   272  	if string(test) != cpContainerContents {
   273  		c.Errorf("output doesn't match the input for absolute symlink")
   274  	}
   275  
   276  }
   277  
   278  // Test for #5619
   279  // Check that symlinks which are part of the resource path are still relative to the container's rootfs
   280  func (s *DockerSuite) TestCpSymlinkComponent(c *check.C) {
   281  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path")
   282  	if exitCode != 0 {
   283  		c.Fatal("failed to create a container", out)
   284  	}
   285  
   286  	cleanedContainerID := strings.TrimSpace(out)
   287  
   288  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   289  	if strings.TrimSpace(out) != "0" {
   290  		c.Fatal("failed to set up container", out)
   291  	}
   292  
   293  	if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
   294  		c.Fatal(err)
   295  	}
   296  
   297  	hostFile, err := os.Create(cpFullPath)
   298  	if err != nil {
   299  		c.Fatal(err)
   300  	}
   301  	defer hostFile.Close()
   302  	defer os.RemoveAll(cpTestPathParent)
   303  
   304  	fmt.Fprintf(hostFile, "%s", cpHostContents)
   305  
   306  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   307  
   308  	if err != nil {
   309  		c.Fatal(err)
   310  	}
   311  
   312  	tmpname := filepath.Join(tmpdir, cpTestName)
   313  	defer os.RemoveAll(tmpdir)
   314  
   315  	path := path.Join("/", "container_path", cpTestName)
   316  
   317  	dockerCmd(c, "cp", cleanedContainerID+":"+path, tmpdir)
   318  
   319  	file, _ := os.Open(tmpname)
   320  	defer file.Close()
   321  
   322  	test, err := ioutil.ReadAll(file)
   323  	if err != nil {
   324  		c.Fatal(err)
   325  	}
   326  
   327  	if string(test) == cpHostContents {
   328  		c.Errorf("output matched host file -- symlink path component can escape container rootfs")
   329  	}
   330  
   331  	if string(test) != cpContainerContents {
   332  		c.Errorf("output doesn't match the input for symlink path component")
   333  	}
   334  
   335  }
   336  
   337  // Check that cp with unprivileged user doesn't return any error
   338  func (s *DockerSuite) TestCpUnprivilegedUser(c *check.C) {
   339  	testRequires(c, UnixCli) // uses chmod/su: not available on windows
   340  
   341  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
   342  	if exitCode != 0 {
   343  		c.Fatal("failed to create a container", out)
   344  	}
   345  
   346  	cleanedContainerID := strings.TrimSpace(out)
   347  
   348  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   349  	if strings.TrimSpace(out) != "0" {
   350  		c.Fatal("failed to set up container", out)
   351  	}
   352  
   353  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   354  	if err != nil {
   355  		c.Fatal(err)
   356  	}
   357  
   358  	defer os.RemoveAll(tmpdir)
   359  
   360  	if err = os.Chmod(tmpdir, 0777); err != nil {
   361  		c.Fatal(err)
   362  	}
   363  
   364  	path := cpTestName
   365  
   366  	_, _, err = runCommandWithOutput(exec.Command("su", "unprivilegeduser", "-c", dockerBinary+" cp "+cleanedContainerID+":"+path+" "+tmpdir))
   367  	if err != nil {
   368  		c.Fatalf("couldn't copy with unprivileged user: %s:%s %s", cleanedContainerID, path, err)
   369  	}
   370  
   371  }
   372  
   373  func (s *DockerSuite) TestCpSpecialFiles(c *check.C) {
   374  	testRequires(c, SameHostDaemon)
   375  
   376  	outDir, err := ioutil.TempDir("", "cp-test-special-files")
   377  	if err != nil {
   378  		c.Fatal(err)
   379  	}
   380  	defer os.RemoveAll(outDir)
   381  
   382  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo")
   383  	if exitCode != 0 {
   384  		c.Fatal("failed to create a container", out)
   385  	}
   386  
   387  	cleanedContainerID := strings.TrimSpace(out)
   388  
   389  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   390  	if strings.TrimSpace(out) != "0" {
   391  		c.Fatal("failed to set up container", out)
   392  	}
   393  
   394  	// Copy actual /etc/resolv.conf
   395  	dockerCmd(c, "cp", cleanedContainerID+":/etc/resolv.conf", outDir)
   396  
   397  	expected, err := ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/resolv.conf")
   398  	actual, err := ioutil.ReadFile(outDir + "/resolv.conf")
   399  
   400  	if !bytes.Equal(actual, expected) {
   401  		c.Fatalf("Expected copied file to be duplicate of the container resolvconf")
   402  	}
   403  
   404  	// Copy actual /etc/hosts
   405  	dockerCmd(c, "cp", cleanedContainerID+":/etc/hosts", outDir)
   406  
   407  	expected, err = ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/hosts")
   408  	actual, err = ioutil.ReadFile(outDir + "/hosts")
   409  
   410  	if !bytes.Equal(actual, expected) {
   411  		c.Fatalf("Expected copied file to be duplicate of the container hosts")
   412  	}
   413  
   414  	// Copy actual /etc/resolv.conf
   415  	dockerCmd(c, "cp", cleanedContainerID+":/etc/hostname", outDir)
   416  
   417  	expected, err = ioutil.ReadFile("/var/lib/docker/containers/" + cleanedContainerID + "/hostname")
   418  	actual, err = ioutil.ReadFile(outDir + "/hostname")
   419  
   420  	if !bytes.Equal(actual, expected) {
   421  		c.Fatalf("Expected copied file to be duplicate of the container resolvconf")
   422  	}
   423  
   424  }
   425  
   426  func (s *DockerSuite) TestCpVolumePath(c *check.C) {
   427  	testRequires(c, SameHostDaemon)
   428  
   429  	tmpDir, err := ioutil.TempDir("", "cp-test-volumepath")
   430  	if err != nil {
   431  		c.Fatal(err)
   432  	}
   433  	defer os.RemoveAll(tmpDir)
   434  	outDir, err := ioutil.TempDir("", "cp-test-volumepath-out")
   435  	if err != nil {
   436  		c.Fatal(err)
   437  	}
   438  	defer os.RemoveAll(outDir)
   439  	_, err = os.Create(tmpDir + "/test")
   440  	if err != nil {
   441  		c.Fatal(err)
   442  	}
   443  
   444  	out, exitCode := dockerCmd(c, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar")
   445  	if exitCode != 0 {
   446  		c.Fatal("failed to create a container", out)
   447  	}
   448  
   449  	cleanedContainerID := strings.TrimSpace(out)
   450  
   451  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   452  	if strings.TrimSpace(out) != "0" {
   453  		c.Fatal("failed to set up container", out)
   454  	}
   455  
   456  	// Copy actual volume path
   457  	dockerCmd(c, "cp", cleanedContainerID+":/foo", outDir)
   458  
   459  	stat, err := os.Stat(outDir + "/foo")
   460  	if err != nil {
   461  		c.Fatal(err)
   462  	}
   463  	if !stat.IsDir() {
   464  		c.Fatal("expected copied content to be dir")
   465  	}
   466  	stat, err = os.Stat(outDir + "/foo/bar")
   467  	if err != nil {
   468  		c.Fatal(err)
   469  	}
   470  	if stat.IsDir() {
   471  		c.Fatal("Expected file `bar` to be a file")
   472  	}
   473  
   474  	// Copy file nested in volume
   475  	dockerCmd(c, "cp", cleanedContainerID+":/foo/bar", outDir)
   476  
   477  	stat, err = os.Stat(outDir + "/bar")
   478  	if err != nil {
   479  		c.Fatal(err)
   480  	}
   481  	if stat.IsDir() {
   482  		c.Fatal("Expected file `bar` to be a file")
   483  	}
   484  
   485  	// Copy Bind-mounted dir
   486  	dockerCmd(c, "cp", cleanedContainerID+":/baz", outDir)
   487  	stat, err = os.Stat(outDir + "/baz")
   488  	if err != nil {
   489  		c.Fatal(err)
   490  	}
   491  	if !stat.IsDir() {
   492  		c.Fatal("Expected `baz` to be a dir")
   493  	}
   494  
   495  	// Copy file nested in bind-mounted dir
   496  	dockerCmd(c, "cp", cleanedContainerID+":/baz/test", outDir)
   497  	fb, err := ioutil.ReadFile(outDir + "/baz/test")
   498  	if err != nil {
   499  		c.Fatal(err)
   500  	}
   501  	fb2, err := ioutil.ReadFile(tmpDir + "/test")
   502  	if err != nil {
   503  		c.Fatal(err)
   504  	}
   505  	if !bytes.Equal(fb, fb2) {
   506  		c.Fatalf("Expected copied file to be duplicate of bind-mounted file")
   507  	}
   508  
   509  	// Copy bind-mounted file
   510  	dockerCmd(c, "cp", cleanedContainerID+":/test", outDir)
   511  	fb, err = ioutil.ReadFile(outDir + "/test")
   512  	if err != nil {
   513  		c.Fatal(err)
   514  	}
   515  	fb2, err = ioutil.ReadFile(tmpDir + "/test")
   516  	if err != nil {
   517  		c.Fatal(err)
   518  	}
   519  	if !bytes.Equal(fb, fb2) {
   520  		c.Fatalf("Expected copied file to be duplicate of bind-mounted file")
   521  	}
   522  
   523  }
   524  
   525  func (s *DockerSuite) TestCpToDot(c *check.C) {
   526  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
   527  	if exitCode != 0 {
   528  		c.Fatal("failed to create a container", out)
   529  	}
   530  
   531  	cleanedContainerID := strings.TrimSpace(out)
   532  
   533  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   534  	if strings.TrimSpace(out) != "0" {
   535  		c.Fatal("failed to set up container", out)
   536  	}
   537  
   538  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   539  	if err != nil {
   540  		c.Fatal(err)
   541  	}
   542  	defer os.RemoveAll(tmpdir)
   543  	cwd, err := os.Getwd()
   544  	if err != nil {
   545  		c.Fatal(err)
   546  	}
   547  	defer os.Chdir(cwd)
   548  	if err := os.Chdir(tmpdir); err != nil {
   549  		c.Fatal(err)
   550  	}
   551  	dockerCmd(c, "cp", cleanedContainerID+":/test", ".")
   552  	content, err := ioutil.ReadFile("./test")
   553  	if string(content) != "lololol\n" {
   554  		c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
   555  	}
   556  }
   557  
   558  func (s *DockerSuite) TestCpToStdout(c *check.C) {
   559  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
   560  	if exitCode != 0 {
   561  		c.Fatalf("failed to create a container:%s\n", out)
   562  	}
   563  
   564  	cID := strings.TrimSpace(out)
   565  
   566  	out, _ = dockerCmd(c, "wait", cID)
   567  	if strings.TrimSpace(out) != "0" {
   568  		c.Fatalf("failed to set up container:%s\n", out)
   569  	}
   570  
   571  	out, _, err := runCommandPipelineWithOutput(
   572  		exec.Command(dockerBinary, "cp", cID+":/test", "-"),
   573  		exec.Command("tar", "-vtf", "-"))
   574  
   575  	if err != nil {
   576  		c.Fatalf("Failed to run commands: %s", err)
   577  	}
   578  
   579  	if !strings.Contains(out, "test") || !strings.Contains(out, "-rw") {
   580  		c.Fatalf("Missing file from tar TOC:\n%s", out)
   581  	}
   582  }
   583  
   584  func (s *DockerSuite) TestCpNameHasColon(c *check.C) {
   585  	testRequires(c, SameHostDaemon)
   586  
   587  	out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /te:s:t")
   588  	if exitCode != 0 {
   589  		c.Fatal("failed to create a container", out)
   590  	}
   591  
   592  	cleanedContainerID := strings.TrimSpace(out)
   593  
   594  	out, _ = dockerCmd(c, "wait", cleanedContainerID)
   595  	if strings.TrimSpace(out) != "0" {
   596  		c.Fatal("failed to set up container", out)
   597  	}
   598  
   599  	tmpdir, err := ioutil.TempDir("", "docker-integration")
   600  	if err != nil {
   601  		c.Fatal(err)
   602  	}
   603  	defer os.RemoveAll(tmpdir)
   604  	dockerCmd(c, "cp", cleanedContainerID+":/te:s:t", tmpdir)
   605  	content, err := ioutil.ReadFile(tmpdir + "/te:s:t")
   606  	if string(content) != "lololol\n" {
   607  		c.Fatalf("Wrong content in copied file %q, should be %q", content, "lololol\n")
   608  	}
   609  }
   610  
   611  func (s *DockerSuite) TestCopyAndRestart(c *check.C) {
   612  	expectedMsg := "hello"
   613  	out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", expectedMsg)
   614  	id := strings.TrimSpace(string(out))
   615  
   616  	out, _ = dockerCmd(c, "wait", id)
   617  
   618  	status := strings.TrimSpace(out)
   619  	if status != "0" {
   620  		c.Fatalf("container exited with status %s", status)
   621  	}
   622  
   623  	tmpDir, err := ioutil.TempDir("", "test-docker-restart-after-copy-")
   624  	if err != nil {
   625  		c.Fatalf("unable to make temporary directory: %s", err)
   626  	}
   627  	defer os.RemoveAll(tmpDir)
   628  
   629  	dockerCmd(c, "cp", fmt.Sprintf("%s:/etc/issue", id), tmpDir)
   630  
   631  	out, _ = dockerCmd(c, "start", "-a", id)
   632  
   633  	msg := strings.TrimSpace(out)
   634  	if msg != expectedMsg {
   635  		c.Fatalf("expected %q but got %q", expectedMsg, msg)
   636  	}
   637  }
   638  
   639  func (s *DockerSuite) TestCopyCreatedContainer(c *check.C) {
   640  	dockerCmd(c, "create", "--name", "test_cp", "-v", "/test", "busybox")
   641  
   642  	tmpDir, err := ioutil.TempDir("", "test")
   643  	if err != nil {
   644  		c.Fatalf("unable to make temporary directory: %s", err)
   645  	}
   646  	defer os.RemoveAll(tmpDir)
   647  	dockerCmd(c, "cp", "test_cp:/bin/sh", tmpDir)
   648  }