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