github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/container/container_unix.go (about) 1 // +build linux freebsd 2 3 package container 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "net" 9 "os" 10 "path/filepath" 11 "strconv" 12 "strings" 13 "syscall" 14 15 "github.com/Sirupsen/logrus" 16 "github.com/docker/docker/daemon/execdriver" 17 derr "github.com/docker/docker/errors" 18 "github.com/docker/docker/pkg/chrootarchive" 19 "github.com/docker/docker/pkg/symlink" 20 "github.com/docker/docker/pkg/system" 21 runconfigopts "github.com/docker/docker/runconfig/opts" 22 "github.com/docker/docker/utils" 23 "github.com/docker/docker/volume" 24 "github.com/docker/engine-api/types/container" 25 "github.com/docker/engine-api/types/network" 26 "github.com/docker/go-connections/nat" 27 "github.com/docker/libnetwork" 28 "github.com/docker/libnetwork/netlabel" 29 "github.com/docker/libnetwork/options" 30 "github.com/docker/libnetwork/types" 31 "github.com/opencontainers/runc/libcontainer/label" 32 ) 33 34 // DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container 35 const DefaultSHMSize int64 = 67108864 36 37 // Container holds the fields specific to unixen implementations. 38 // See CommonContainer for standard fields common to all containers. 39 type Container struct { 40 CommonContainer 41 42 // Fields below here are platform specific. 43 AppArmorProfile string 44 HostnamePath string 45 HostsPath string 46 ShmPath string 47 MqueuePath string 48 ResolvConfPath string 49 SeccompProfile string 50 } 51 52 // CreateDaemonEnvironment returns the list of all environment variables given the list of 53 // environment variables related to links. 54 // Sets PATH, HOSTNAME and if container.Config.Tty is set: TERM. 55 // The defaults set here do not override the values in container.Config.Env 56 func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string { 57 // if a domain name was specified, append it to the hostname (see #7851) 58 fullHostname := container.Config.Hostname 59 if container.Config.Domainname != "" { 60 fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname) 61 } 62 // Setup environment 63 env := []string{ 64 "PATH=" + system.DefaultPathEnv, 65 "HOSTNAME=" + fullHostname, 66 // Note: we don't set HOME here because it'll get autoset intelligently 67 // based on the value of USER inside dockerinit, but only if it isn't 68 // set already (ie, that can be overridden by setting HOME via -e or ENV 69 // in a Dockerfile). 70 } 71 if container.Config.Tty { 72 env = append(env, "TERM=xterm") 73 } 74 env = append(env, linkedEnv...) 75 // because the env on the container can override certain default values 76 // we need to replace the 'env' keys where they match and append anything 77 // else. 78 env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env) 79 80 return env 81 } 82 83 // TrySetNetworkMount attempts to set the network mounts given a provided destination and 84 // the path to use for it; return true if the given destination was a network mount file 85 func (container *Container) TrySetNetworkMount(destination string, path string) bool { 86 if destination == "/etc/resolv.conf" { 87 container.ResolvConfPath = path 88 return true 89 } 90 if destination == "/etc/hostname" { 91 container.HostnamePath = path 92 return true 93 } 94 if destination == "/etc/hosts" { 95 container.HostsPath = path 96 return true 97 } 98 99 return false 100 } 101 102 // BuildHostnameFile writes the container's hostname file. 103 func (container *Container) BuildHostnameFile() error { 104 hostnamePath, err := container.GetRootResourcePath("hostname") 105 if err != nil { 106 return err 107 } 108 container.HostnamePath = hostnamePath 109 110 if container.Config.Domainname != "" { 111 return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644) 112 } 113 return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) 114 } 115 116 // GetEndpointInNetwork returns the container's endpoint to the provided network. 117 func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) { 118 endpointName := strings.TrimPrefix(container.Name, "/") 119 return n.EndpointByName(endpointName) 120 } 121 122 func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error { 123 if ep == nil { 124 return derr.ErrorCodeEmptyEndpoint 125 } 126 127 networkSettings := container.NetworkSettings 128 if networkSettings == nil { 129 return derr.ErrorCodeEmptyNetwork 130 } 131 132 driverInfo, err := ep.DriverInfo() 133 if err != nil { 134 return err 135 } 136 137 if driverInfo == nil { 138 // It is not an error for epInfo to be nil 139 return nil 140 } 141 142 if networkSettings.Ports == nil { 143 networkSettings.Ports = nat.PortMap{} 144 } 145 146 if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { 147 if exposedPorts, ok := expData.([]types.TransportPort); ok { 148 for _, tp := range exposedPorts { 149 natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) 150 if err != nil { 151 return derr.ErrorCodeParsingPort.WithArgs(tp.Port, err) 152 } 153 networkSettings.Ports[natPort] = nil 154 } 155 } 156 } 157 158 mapData, ok := driverInfo[netlabel.PortMap] 159 if !ok { 160 return nil 161 } 162 163 if portMapping, ok := mapData.([]types.PortBinding); ok { 164 for _, pp := range portMapping { 165 natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) 166 if err != nil { 167 return err 168 } 169 natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} 170 networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg) 171 } 172 } 173 174 return nil 175 } 176 177 // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint. 178 func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { 179 if ep == nil { 180 return derr.ErrorCodeEmptyEndpoint 181 } 182 183 networkSettings := container.NetworkSettings 184 if networkSettings == nil { 185 return derr.ErrorCodeEmptyNetwork 186 } 187 188 epInfo := ep.Info() 189 if epInfo == nil { 190 // It is not an error to get an empty endpoint info 191 return nil 192 } 193 194 if _, ok := networkSettings.Networks[n.Name()]; !ok { 195 networkSettings.Networks[n.Name()] = new(network.EndpointSettings) 196 } 197 networkSettings.Networks[n.Name()].NetworkID = n.ID() 198 networkSettings.Networks[n.Name()].EndpointID = ep.ID() 199 200 iface := epInfo.Iface() 201 if iface == nil { 202 return nil 203 } 204 205 if iface.MacAddress() != nil { 206 networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String() 207 } 208 209 if iface.Address() != nil { 210 ones, _ := iface.Address().Mask.Size() 211 networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String() 212 networkSettings.Networks[n.Name()].IPPrefixLen = ones 213 } 214 215 if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { 216 onesv6, _ := iface.AddressIPv6().Mask.Size() 217 networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String() 218 networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6 219 } 220 221 return nil 222 } 223 224 // UpdateJoinInfo updates network settings when container joins network n with endpoint ep. 225 func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { 226 if err := container.buildPortMapInfo(ep); err != nil { 227 return err 228 } 229 230 epInfo := ep.Info() 231 if epInfo == nil { 232 // It is not an error to get an empty endpoint info 233 return nil 234 } 235 if epInfo.Gateway() != nil { 236 container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() 237 } 238 if epInfo.GatewayIPv6().To16() != nil { 239 container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() 240 } 241 242 return nil 243 } 244 245 // UpdateSandboxNetworkSettings updates the sandbox ID and Key. 246 func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error { 247 container.NetworkSettings.SandboxID = sb.ID() 248 container.NetworkSettings.SandboxKey = sb.Key() 249 return nil 250 } 251 252 // BuildJoinOptions builds endpoint Join options from a given network. 253 func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) { 254 var joinOptions []libnetwork.EndpointOption 255 if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok { 256 for _, str := range epConfig.Links { 257 name, alias, err := runconfigopts.ParseLink(str) 258 if err != nil { 259 return nil, err 260 } 261 joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias)) 262 } 263 } 264 return joinOptions, nil 265 } 266 267 // BuildCreateEndpointOptions builds endpoint options from a given network. 268 func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) { 269 var ( 270 portSpecs = make(nat.PortSet) 271 bindings = make(nat.PortMap) 272 pbList []types.PortBinding 273 exposeList []types.TransportPort 274 createOptions []libnetwork.EndpointOption 275 ) 276 277 if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint { 278 createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) 279 } 280 281 if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok { 282 ipam := epConfig.IPAMConfig 283 if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") { 284 createOptions = append(createOptions, 285 libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil)) 286 } 287 288 for _, alias := range epConfig.Aliases { 289 createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) 290 } 291 } 292 293 if !container.HostConfig.NetworkMode.IsUserDefined() { 294 createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) 295 } 296 297 // Other configs are applicable only for the endpoint in the network 298 // to which container was connected to on docker run. 299 if n.Name() != container.HostConfig.NetworkMode.NetworkName() && 300 !(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) { 301 return createOptions, nil 302 } 303 304 if container.Config.ExposedPorts != nil { 305 portSpecs = container.Config.ExposedPorts 306 } 307 308 if container.HostConfig.PortBindings != nil { 309 for p, b := range container.HostConfig.PortBindings { 310 bindings[p] = []nat.PortBinding{} 311 for _, bb := range b { 312 bindings[p] = append(bindings[p], nat.PortBinding{ 313 HostIP: bb.HostIP, 314 HostPort: bb.HostPort, 315 }) 316 } 317 } 318 } 319 320 ports := make([]nat.Port, len(portSpecs)) 321 var i int 322 for p := range portSpecs { 323 ports[i] = p 324 i++ 325 } 326 nat.SortPortMap(ports, bindings) 327 for _, port := range ports { 328 expose := types.TransportPort{} 329 expose.Proto = types.ParseProtocol(port.Proto()) 330 expose.Port = uint16(port.Int()) 331 exposeList = append(exposeList, expose) 332 333 pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} 334 binding := bindings[port] 335 for i := 0; i < len(binding); i++ { 336 pbCopy := pb.GetCopy() 337 newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) 338 var portStart, portEnd int 339 if err == nil { 340 portStart, portEnd, err = newP.Range() 341 } 342 if err != nil { 343 return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) 344 } 345 pbCopy.HostPort = uint16(portStart) 346 pbCopy.HostPortEnd = uint16(portEnd) 347 pbCopy.HostIP = net.ParseIP(binding[i].HostIP) 348 pbList = append(pbList, pbCopy) 349 } 350 351 if container.HostConfig.PublishAllPorts && len(binding) == 0 { 352 pbList = append(pbList, pb) 353 } 354 } 355 356 createOptions = append(createOptions, 357 libnetwork.CreateOptionPortMapping(pbList), 358 libnetwork.CreateOptionExposedPorts(exposeList)) 359 360 if container.Config.MacAddress != "" { 361 mac, err := net.ParseMAC(container.Config.MacAddress) 362 if err != nil { 363 return nil, err 364 } 365 366 genericOption := options.Generic{ 367 netlabel.MacAddress: mac, 368 } 369 370 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) 371 } 372 373 return createOptions, nil 374 } 375 376 // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir 377 func (container *Container) SetupWorkingDirectory() error { 378 if container.Config.WorkingDir == "" { 379 return nil 380 } 381 container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) 382 383 pth, err := container.GetResourcePath(container.Config.WorkingDir) 384 if err != nil { 385 return err 386 } 387 388 pthInfo, err := os.Stat(pth) 389 if err != nil { 390 if !os.IsNotExist(err) { 391 return err 392 } 393 394 if err := system.MkdirAll(pth, 0755); err != nil { 395 return err 396 } 397 } 398 if pthInfo != nil && !pthInfo.IsDir() { 399 return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) 400 } 401 return nil 402 } 403 404 // appendNetworkMounts appends any network mounts to the array of mount points passed in 405 func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) { 406 for _, mnt := range container.NetworkMounts() { 407 dest, err := container.GetResourcePath(mnt.Destination) 408 if err != nil { 409 return nil, err 410 } 411 volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest}) 412 } 413 return volumeMounts, nil 414 } 415 416 // NetworkMounts returns the list of network mounts. 417 func (container *Container) NetworkMounts() []execdriver.Mount { 418 var mounts []execdriver.Mount 419 shared := container.HostConfig.NetworkMode.IsContainer() 420 if container.ResolvConfPath != "" { 421 if _, err := os.Stat(container.ResolvConfPath); err != nil { 422 logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err) 423 } else { 424 label.Relabel(container.ResolvConfPath, container.MountLabel, shared) 425 writable := !container.HostConfig.ReadonlyRootfs 426 if m, exists := container.MountPoints["/etc/resolv.conf"]; exists { 427 writable = m.RW 428 } 429 mounts = append(mounts, execdriver.Mount{ 430 Source: container.ResolvConfPath, 431 Destination: "/etc/resolv.conf", 432 Writable: writable, 433 Propagation: volume.DefaultPropagationMode, 434 }) 435 } 436 } 437 if container.HostnamePath != "" { 438 if _, err := os.Stat(container.HostnamePath); err != nil { 439 logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err) 440 } else { 441 label.Relabel(container.HostnamePath, container.MountLabel, shared) 442 writable := !container.HostConfig.ReadonlyRootfs 443 if m, exists := container.MountPoints["/etc/hostname"]; exists { 444 writable = m.RW 445 } 446 mounts = append(mounts, execdriver.Mount{ 447 Source: container.HostnamePath, 448 Destination: "/etc/hostname", 449 Writable: writable, 450 Propagation: volume.DefaultPropagationMode, 451 }) 452 } 453 } 454 if container.HostsPath != "" { 455 if _, err := os.Stat(container.HostsPath); err != nil { 456 logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err) 457 } else { 458 label.Relabel(container.HostsPath, container.MountLabel, shared) 459 writable := !container.HostConfig.ReadonlyRootfs 460 if m, exists := container.MountPoints["/etc/hosts"]; exists { 461 writable = m.RW 462 } 463 mounts = append(mounts, execdriver.Mount{ 464 Source: container.HostsPath, 465 Destination: "/etc/hosts", 466 Writable: writable, 467 Propagation: volume.DefaultPropagationMode, 468 }) 469 } 470 } 471 return mounts 472 } 473 474 // CopyImagePathContent copies files in destination to the volume. 475 func (container *Container) CopyImagePathContent(v volume.Volume, destination string) error { 476 rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, destination), container.BaseFS) 477 if err != nil { 478 return err 479 } 480 481 if _, err = ioutil.ReadDir(rootfs); err != nil { 482 if os.IsNotExist(err) { 483 return nil 484 } 485 return err 486 } 487 488 path, err := v.Mount() 489 if err != nil { 490 return err 491 } 492 493 if err := copyExistingContents(rootfs, path); err != nil { 494 return err 495 } 496 497 return v.Unmount() 498 } 499 500 // ShmResourcePath returns path to shm 501 func (container *Container) ShmResourcePath() (string, error) { 502 return container.GetRootResourcePath("shm") 503 } 504 505 // MqueueResourcePath returns path to mqueue 506 func (container *Container) MqueueResourcePath() (string, error) { 507 return container.GetRootResourcePath("mqueue") 508 } 509 510 // HasMountFor checks if path is a mountpoint 511 func (container *Container) HasMountFor(path string) bool { 512 _, exists := container.MountPoints[path] 513 return exists 514 } 515 516 // UnmountIpcMounts uses the provided unmount function to unmount shm and mqueue if they were mounted 517 func (container *Container) UnmountIpcMounts(unmount func(pth string) error) { 518 if container.HostConfig.IpcMode.IsContainer() || container.HostConfig.IpcMode.IsHost() { 519 return 520 } 521 522 var warnings []string 523 524 if !container.HasMountFor("/dev/shm") { 525 shmPath, err := container.ShmResourcePath() 526 if err != nil { 527 logrus.Error(err) 528 warnings = append(warnings, err.Error()) 529 } else if shmPath != "" { 530 if err := unmount(shmPath); err != nil { 531 warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err)) 532 } 533 534 } 535 } 536 537 if !container.HasMountFor("/dev/mqueue") { 538 mqueuePath, err := container.MqueueResourcePath() 539 if err != nil { 540 logrus.Error(err) 541 warnings = append(warnings, err.Error()) 542 } else if mqueuePath != "" { 543 if err := unmount(mqueuePath); err != nil { 544 warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", mqueuePath, err)) 545 } 546 } 547 } 548 549 if len(warnings) > 0 { 550 logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n")) 551 } 552 } 553 554 // IpcMounts returns the list of IPC mounts 555 func (container *Container) IpcMounts() []execdriver.Mount { 556 var mounts []execdriver.Mount 557 558 if !container.HasMountFor("/dev/shm") { 559 label.SetFileLabel(container.ShmPath, container.MountLabel) 560 mounts = append(mounts, execdriver.Mount{ 561 Source: container.ShmPath, 562 Destination: "/dev/shm", 563 Writable: true, 564 Propagation: volume.DefaultPropagationMode, 565 }) 566 } 567 568 if !container.HasMountFor("/dev/mqueue") { 569 label.SetFileLabel(container.MqueuePath, container.MountLabel) 570 mounts = append(mounts, execdriver.Mount{ 571 Source: container.MqueuePath, 572 Destination: "/dev/mqueue", 573 Writable: true, 574 Propagation: volume.DefaultPropagationMode, 575 }) 576 } 577 return mounts 578 } 579 580 func updateCommand(c *execdriver.Command, resources container.Resources) { 581 c.Resources.BlkioWeight = resources.BlkioWeight 582 c.Resources.CPUShares = resources.CPUShares 583 c.Resources.CPUPeriod = resources.CPUPeriod 584 c.Resources.CPUQuota = resources.CPUQuota 585 c.Resources.CpusetCpus = resources.CpusetCpus 586 c.Resources.CpusetMems = resources.CpusetMems 587 c.Resources.Memory = resources.Memory 588 c.Resources.MemorySwap = resources.MemorySwap 589 c.Resources.MemoryReservation = resources.MemoryReservation 590 c.Resources.KernelMemory = resources.KernelMemory 591 } 592 593 // UpdateContainer updates resources of a container. 594 func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error { 595 container.Lock() 596 597 resources := hostConfig.Resources 598 cResources := &container.HostConfig.Resources 599 if resources.BlkioWeight != 0 { 600 cResources.BlkioWeight = resources.BlkioWeight 601 } 602 if resources.CPUShares != 0 { 603 cResources.CPUShares = resources.CPUShares 604 } 605 if resources.CPUPeriod != 0 { 606 cResources.CPUPeriod = resources.CPUPeriod 607 } 608 if resources.CPUQuota != 0 { 609 cResources.CPUQuota = resources.CPUQuota 610 } 611 if resources.CpusetCpus != "" { 612 cResources.CpusetCpus = resources.CpusetCpus 613 } 614 if resources.CpusetMems != "" { 615 cResources.CpusetMems = resources.CpusetMems 616 } 617 if resources.Memory != 0 { 618 cResources.Memory = resources.Memory 619 } 620 if resources.MemorySwap != 0 { 621 cResources.MemorySwap = resources.MemorySwap 622 } 623 if resources.MemoryReservation != 0 { 624 cResources.MemoryReservation = resources.MemoryReservation 625 } 626 if resources.KernelMemory != 0 { 627 cResources.KernelMemory = resources.KernelMemory 628 } 629 container.Unlock() 630 631 // If container is not running, update hostConfig struct is enough, 632 // resources will be updated when the container is started again. 633 // If container is running (including paused), we need to update 634 // the command so we can update configs to the real world. 635 if container.IsRunning() { 636 container.Lock() 637 updateCommand(container.Command, *cResources) 638 container.Unlock() 639 } 640 641 if err := container.ToDiskLocking(); err != nil { 642 logrus.Errorf("Error saving updated container: %v", err) 643 return err 644 } 645 646 return nil 647 } 648 649 func detachMounted(path string) error { 650 return syscall.Unmount(path, syscall.MNT_DETACH) 651 } 652 653 // UnmountVolumes unmounts all volumes 654 func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error { 655 var ( 656 volumeMounts []volume.MountPoint 657 err error 658 ) 659 660 for _, mntPoint := range container.MountPoints { 661 dest, err := container.GetResourcePath(mntPoint.Destination) 662 if err != nil { 663 return err 664 } 665 666 volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume}) 667 } 668 669 // Append any network mounts to the list (this is a no-op on Windows) 670 if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil { 671 return err 672 } 673 674 for _, volumeMount := range volumeMounts { 675 if forceSyscall { 676 if err := detachMounted(volumeMount.Destination); err != nil { 677 logrus.Warnf("%s unmountVolumes: Failed to do lazy umount %v", container.ID, err) 678 } 679 } 680 681 if volumeMount.Volume != nil { 682 if err := volumeMount.Volume.Unmount(); err != nil { 683 return err 684 } 685 686 attributes := map[string]string{ 687 "driver": volumeMount.Volume.DriverName(), 688 "container": container.ID, 689 } 690 volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes) 691 } 692 } 693 694 return nil 695 } 696 697 // copyExistingContents copies from the source to the destination and 698 // ensures the ownership is appropriately set. 699 func copyExistingContents(source, destination string) error { 700 volList, err := ioutil.ReadDir(source) 701 if err != nil { 702 return err 703 } 704 if len(volList) > 0 { 705 srcList, err := ioutil.ReadDir(destination) 706 if err != nil { 707 return err 708 } 709 if len(srcList) == 0 { 710 // If the source volume is empty, copies files from the root into the volume 711 if err := chrootarchive.CopyWithTar(source, destination); err != nil { 712 return err 713 } 714 } 715 } 716 return copyOwnership(source, destination) 717 } 718 719 // copyOwnership copies the permissions and uid:gid of the source file 720 // to the destination file 721 func copyOwnership(source, destination string) error { 722 stat, err := system.Stat(source) 723 if err != nil { 724 return err 725 } 726 727 if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil { 728 return err 729 } 730 731 return os.Chmod(destination, os.FileMode(stat.Mode())) 732 } 733 734 // TmpfsMounts returns the list of tmpfs mounts 735 func (container *Container) TmpfsMounts() []execdriver.Mount { 736 var mounts []execdriver.Mount 737 for dest, data := range container.HostConfig.Tmpfs { 738 mounts = append(mounts, execdriver.Mount{ 739 Source: "tmpfs", 740 Destination: dest, 741 Data: data, 742 }) 743 } 744 return mounts 745 }