github.com/fntlnz/docker@v1.9.0-rc3/daemon/container_unix.go (about)

     1  // +build linux freebsd
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net"
     9  	"os"
    10  	"path"
    11  	"path/filepath"
    12  	"strconv"
    13  	"strings"
    14  	"syscall"
    15  	"time"
    16  
    17  	"github.com/Sirupsen/logrus"
    18  	"github.com/docker/docker/daemon/execdriver"
    19  	"github.com/docker/docker/daemon/links"
    20  	"github.com/docker/docker/daemon/network"
    21  	derr "github.com/docker/docker/errors"
    22  	"github.com/docker/docker/pkg/directory"
    23  	"github.com/docker/docker/pkg/idtools"
    24  	"github.com/docker/docker/pkg/nat"
    25  	"github.com/docker/docker/pkg/stringid"
    26  	"github.com/docker/docker/pkg/system"
    27  	"github.com/docker/docker/pkg/ulimit"
    28  	"github.com/docker/docker/runconfig"
    29  	"github.com/docker/docker/utils"
    30  	"github.com/docker/docker/volume"
    31  	"github.com/docker/docker/volume/store"
    32  	"github.com/docker/libnetwork"
    33  	"github.com/docker/libnetwork/drivers/bridge"
    34  	"github.com/docker/libnetwork/netlabel"
    35  	"github.com/docker/libnetwork/options"
    36  	"github.com/docker/libnetwork/types"
    37  	"github.com/opencontainers/runc/libcontainer/configs"
    38  	"github.com/opencontainers/runc/libcontainer/devices"
    39  	"github.com/opencontainers/runc/libcontainer/label"
    40  )
    41  
    42  // DefaultPathEnv is unix style list of directories to search for
    43  // executables. Each directory is separated from the next by a colon
    44  // ':' character .
    45  const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    46  
    47  // Container holds the fields specific to unixen implementations. See
    48  // CommonContainer for standard fields common to all containers.
    49  type Container struct {
    50  	CommonContainer
    51  
    52  	// Fields below here are platform specific.
    53  	activeLinks     map[string]*links.Link
    54  	AppArmorProfile string
    55  	HostnamePath    string
    56  	HostsPath       string
    57  	ShmPath         string
    58  	MqueuePath      string
    59  	MountPoints     map[string]*mountPoint
    60  	ResolvConfPath  string
    61  
    62  	Volumes   map[string]string // Deprecated since 1.7, kept for backwards compatibility
    63  	VolumesRW map[string]bool   // Deprecated since 1.7, kept for backwards compatibility
    64  }
    65  
    66  func killProcessDirectly(container *Container) error {
    67  	if _, err := container.WaitStop(10 * time.Second); err != nil {
    68  		// Ensure that we don't kill ourselves
    69  		if pid := container.getPID(); pid != 0 {
    70  			logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(container.ID))
    71  			if err := syscall.Kill(pid, 9); err != nil {
    72  				if err != syscall.ESRCH {
    73  					return err
    74  				}
    75  				logrus.Debugf("Cannot kill process (pid=%d) with signal 9: no such process.", pid)
    76  			}
    77  		}
    78  	}
    79  	return nil
    80  }
    81  
    82  func (container *Container) setupLinkedContainers() ([]string, error) {
    83  	var (
    84  		env    []string
    85  		daemon = container.daemon
    86  	)
    87  	children, err := daemon.children(container.Name)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	bridgeSettings := container.NetworkSettings.Networks["bridge"]
    93  	if bridgeSettings == nil {
    94  		return nil, nil
    95  	}
    96  
    97  	if len(children) > 0 {
    98  		for linkAlias, child := range children {
    99  			if !child.IsRunning() {
   100  				return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias)
   101  			}
   102  
   103  			childBridgeSettings := child.NetworkSettings.Networks["bridge"]
   104  			if childBridgeSettings == nil {
   105  				return nil, fmt.Errorf("container %d not attached to default bridge network", child.ID)
   106  			}
   107  
   108  			link := links.NewLink(
   109  				bridgeSettings.IPAddress,
   110  				childBridgeSettings.IPAddress,
   111  				linkAlias,
   112  				child.Config.Env,
   113  				child.Config.ExposedPorts,
   114  			)
   115  
   116  			for _, envVar := range link.ToEnv() {
   117  				env = append(env, envVar)
   118  			}
   119  		}
   120  	}
   121  	return env, nil
   122  }
   123  
   124  func (container *Container) createDaemonEnvironment(linkedEnv []string) []string {
   125  	// if a domain name was specified, append it to the hostname (see #7851)
   126  	fullHostname := container.Config.Hostname
   127  	if container.Config.Domainname != "" {
   128  		fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname)
   129  	}
   130  	// Setup environment
   131  	env := []string{
   132  		"PATH=" + DefaultPathEnv,
   133  		"HOSTNAME=" + fullHostname,
   134  		// Note: we don't set HOME here because it'll get autoset intelligently
   135  		// based on the value of USER inside dockerinit, but only if it isn't
   136  		// set already (ie, that can be overridden by setting HOME via -e or ENV
   137  		// in a Dockerfile).
   138  	}
   139  	if container.Config.Tty {
   140  		env = append(env, "TERM=xterm")
   141  	}
   142  	env = append(env, linkedEnv...)
   143  	// because the env on the container can override certain default values
   144  	// we need to replace the 'env' keys where they match and append anything
   145  	// else.
   146  	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
   147  
   148  	return env
   149  }
   150  
   151  func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.Device, err error) {
   152  	device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
   153  	// if there was no error, return the device
   154  	if err == nil {
   155  		device.Path = deviceMapping.PathInContainer
   156  		return append(devs, device), nil
   157  	}
   158  
   159  	// if the device is not a device node
   160  	// try to see if it's a directory holding many devices
   161  	if err == devices.ErrNotADevice {
   162  
   163  		// check if it is a directory
   164  		if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() {
   165  
   166  			// mount the internal devices recursively
   167  			filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error {
   168  				childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions)
   169  				if e != nil {
   170  					// ignore the device
   171  					return nil
   172  				}
   173  
   174  				// add the device to userSpecified devices
   175  				childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1)
   176  				devs = append(devs, childDevice)
   177  
   178  				return nil
   179  			})
   180  		}
   181  	}
   182  
   183  	if len(devs) > 0 {
   184  		return devs, nil
   185  	}
   186  
   187  	return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err)
   188  }
   189  
   190  func populateCommand(c *Container, env []string) error {
   191  	var en *execdriver.Network
   192  	if !c.Config.NetworkDisabled {
   193  		en = &execdriver.Network{}
   194  		if !c.daemon.execDriver.SupportsHooks() || c.hostConfig.NetworkMode.IsHost() {
   195  			en.NamespacePath = c.NetworkSettings.SandboxKey
   196  		}
   197  
   198  		parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
   199  		if parts[0] == "container" {
   200  			nc, err := c.getNetworkedContainer()
   201  			if err != nil {
   202  				return err
   203  			}
   204  			en.ContainerID = nc.ID
   205  		}
   206  	}
   207  
   208  	ipc := &execdriver.Ipc{}
   209  	var err error
   210  	c.ShmPath, err = c.shmPath()
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	c.MqueuePath, err = c.mqueuePath()
   216  	if err != nil {
   217  		return err
   218  	}
   219  
   220  	if c.hostConfig.IpcMode.IsContainer() {
   221  		ic, err := c.getIpcContainer()
   222  		if err != nil {
   223  			return err
   224  		}
   225  		ipc.ContainerID = ic.ID
   226  		c.ShmPath = ic.ShmPath
   227  		c.MqueuePath = ic.MqueuePath
   228  	} else {
   229  		ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
   230  		if ipc.HostIpc {
   231  			if _, err := os.Stat("/dev/shm"); err != nil {
   232  				return fmt.Errorf("/dev/shm is not mounted, but must be for --host=ipc")
   233  			}
   234  			if _, err := os.Stat("/dev/mqueue"); err != nil {
   235  				return fmt.Errorf("/dev/mqueue is not mounted, but must be for --host=ipc")
   236  			}
   237  			c.ShmPath = "/dev/shm"
   238  			c.MqueuePath = "/dev/mqueue"
   239  		}
   240  	}
   241  
   242  	pid := &execdriver.Pid{}
   243  	pid.HostPid = c.hostConfig.PidMode.IsHost()
   244  
   245  	uts := &execdriver.UTS{
   246  		HostUTS: c.hostConfig.UTSMode.IsHost(),
   247  	}
   248  
   249  	// Build lists of devices allowed and created within the container.
   250  	var userSpecifiedDevices []*configs.Device
   251  	for _, deviceMapping := range c.hostConfig.Devices {
   252  		devs, err := getDevicesFromPath(deviceMapping)
   253  		if err != nil {
   254  			return err
   255  		}
   256  
   257  		userSpecifiedDevices = append(userSpecifiedDevices, devs...)
   258  	}
   259  
   260  	allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices)
   261  
   262  	autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
   263  
   264  	// TODO: this can be removed after lxc-conf is fully deprecated
   265  	lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
   266  	if err != nil {
   267  		return err
   268  	}
   269  
   270  	var rlimits []*ulimit.Rlimit
   271  	ulimits := c.hostConfig.Ulimits
   272  
   273  	// Merge ulimits with daemon defaults
   274  	ulIdx := make(map[string]*ulimit.Ulimit)
   275  	for _, ul := range ulimits {
   276  		ulIdx[ul.Name] = ul
   277  	}
   278  	for name, ul := range c.daemon.configStore.Ulimits {
   279  		if _, exists := ulIdx[name]; !exists {
   280  			ulimits = append(ulimits, ul)
   281  		}
   282  	}
   283  
   284  	for _, limit := range ulimits {
   285  		rl, err := limit.GetRlimit()
   286  		if err != nil {
   287  			return err
   288  		}
   289  		rlimits = append(rlimits, rl)
   290  	}
   291  
   292  	resources := &execdriver.Resources{
   293  		Memory:            c.hostConfig.Memory,
   294  		MemorySwap:        c.hostConfig.MemorySwap,
   295  		MemoryReservation: c.hostConfig.MemoryReservation,
   296  		KernelMemory:      c.hostConfig.KernelMemory,
   297  		CPUShares:         c.hostConfig.CPUShares,
   298  		CpusetCpus:        c.hostConfig.CpusetCpus,
   299  		CpusetMems:        c.hostConfig.CpusetMems,
   300  		CPUPeriod:         c.hostConfig.CPUPeriod,
   301  		CPUQuota:          c.hostConfig.CPUQuota,
   302  		BlkioWeight:       c.hostConfig.BlkioWeight,
   303  		Rlimits:           rlimits,
   304  		OomKillDisable:    c.hostConfig.OomKillDisable,
   305  		MemorySwappiness:  -1,
   306  	}
   307  
   308  	if c.hostConfig.MemorySwappiness != nil {
   309  		resources.MemorySwappiness = *c.hostConfig.MemorySwappiness
   310  	}
   311  
   312  	processConfig := execdriver.ProcessConfig{
   313  		Privileged: c.hostConfig.Privileged,
   314  		Entrypoint: c.Path,
   315  		Arguments:  c.Args,
   316  		Tty:        c.Config.Tty,
   317  		User:       c.Config.User,
   318  	}
   319  
   320  	processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
   321  	processConfig.Env = env
   322  
   323  	remappedRoot := &execdriver.User{}
   324  	rootUID, rootGID := c.daemon.GetRemappedUIDGID()
   325  	if rootUID != 0 {
   326  		remappedRoot.UID = rootUID
   327  		remappedRoot.GID = rootGID
   328  	}
   329  	uidMap, gidMap := c.daemon.GetUIDGIDMaps()
   330  
   331  	c.command = &execdriver.Command{
   332  		ID:                 c.ID,
   333  		Rootfs:             c.rootfsPath(),
   334  		ReadonlyRootfs:     c.hostConfig.ReadonlyRootfs,
   335  		InitPath:           "/.dockerinit",
   336  		WorkingDir:         c.Config.WorkingDir,
   337  		Network:            en,
   338  		Ipc:                ipc,
   339  		UIDMapping:         uidMap,
   340  		GIDMapping:         gidMap,
   341  		RemappedRoot:       remappedRoot,
   342  		Pid:                pid,
   343  		UTS:                uts,
   344  		Resources:          resources,
   345  		AllowedDevices:     allowedDevices,
   346  		AutoCreatedDevices: autoCreatedDevices,
   347  		CapAdd:             c.hostConfig.CapAdd.Slice(),
   348  		CapDrop:            c.hostConfig.CapDrop.Slice(),
   349  		GroupAdd:           c.hostConfig.GroupAdd,
   350  		ProcessConfig:      processConfig,
   351  		ProcessLabel:       c.getProcessLabel(),
   352  		MountLabel:         c.getMountLabel(),
   353  		LxcConfig:          lxcConfig,
   354  		AppArmorProfile:    c.AppArmorProfile,
   355  		CgroupParent:       c.hostConfig.CgroupParent,
   356  	}
   357  
   358  	return nil
   359  }
   360  
   361  func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device {
   362  	if len(userDevices) == 0 {
   363  		return defaultDevices
   364  	}
   365  
   366  	paths := map[string]*configs.Device{}
   367  	for _, d := range userDevices {
   368  		paths[d.Path] = d
   369  	}
   370  
   371  	var devs []*configs.Device
   372  	for _, d := range defaultDevices {
   373  		if _, defined := paths[d.Path]; !defined {
   374  			devs = append(devs, d)
   375  		}
   376  	}
   377  	return append(devs, userDevices...)
   378  }
   379  
   380  // GetSize returns the real size & virtual size of the container.
   381  func (container *Container) getSize() (int64, int64) {
   382  	var (
   383  		sizeRw, sizeRootfs int64
   384  		err                error
   385  		driver             = container.daemon.driver
   386  	)
   387  
   388  	if err := container.Mount(); err != nil {
   389  		logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
   390  		return sizeRw, sizeRootfs
   391  	}
   392  	defer container.Unmount()
   393  
   394  	initID := fmt.Sprintf("%s-init", container.ID)
   395  	sizeRw, err = driver.DiffSize(container.ID, initID)
   396  	if err != nil {
   397  		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
   398  		// FIXME: GetSize should return an error. Not changing it now in case
   399  		// there is a side-effect.
   400  		sizeRw = -1
   401  	}
   402  
   403  	if _, err = os.Stat(container.basefs); err == nil {
   404  		if sizeRootfs, err = directory.Size(container.basefs); err != nil {
   405  			sizeRootfs = -1
   406  		}
   407  	}
   408  	return sizeRw, sizeRootfs
   409  }
   410  
   411  // Attempt to set the network mounts given a provided destination and
   412  // the path to use for it; return true if the given destination was a
   413  // network mount file
   414  func (container *Container) trySetNetworkMount(destination string, path string) bool {
   415  	if destination == "/etc/resolv.conf" {
   416  		container.ResolvConfPath = path
   417  		return true
   418  	}
   419  	if destination == "/etc/hostname" {
   420  		container.HostnamePath = path
   421  		return true
   422  	}
   423  	if destination == "/etc/hosts" {
   424  		container.HostsPath = path
   425  		return true
   426  	}
   427  
   428  	return false
   429  }
   430  
   431  func (container *Container) buildHostnameFile() error {
   432  	hostnamePath, err := container.getRootResourcePath("hostname")
   433  	if err != nil {
   434  		return err
   435  	}
   436  	container.HostnamePath = hostnamePath
   437  
   438  	if container.Config.Domainname != "" {
   439  		return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
   440  	}
   441  	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
   442  }
   443  
   444  func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetwork.SandboxOption, error) {
   445  	var (
   446  		sboxOptions []libnetwork.SandboxOption
   447  		err         error
   448  		dns         []string
   449  		dnsSearch   []string
   450  		dnsOptions  []string
   451  	)
   452  
   453  	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
   454  		libnetwork.OptionDomainname(container.Config.Domainname))
   455  
   456  	if container.hostConfig.NetworkMode.IsHost() {
   457  		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
   458  		sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
   459  		sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
   460  	} else if container.daemon.execDriver.SupportsHooks() {
   461  		// OptionUseExternalKey is mandatory for userns support.
   462  		// But optional for non-userns support
   463  		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
   464  	}
   465  
   466  	container.HostsPath, err = container.getRootResourcePath("hosts")
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  	sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
   471  
   472  	container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf")
   473  	if err != nil {
   474  		return nil, err
   475  	}
   476  	sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
   477  
   478  	if len(container.hostConfig.DNS) > 0 {
   479  		dns = container.hostConfig.DNS
   480  	} else if len(container.daemon.configStore.DNS) > 0 {
   481  		dns = container.daemon.configStore.DNS
   482  	}
   483  
   484  	for _, d := range dns {
   485  		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
   486  	}
   487  
   488  	if len(container.hostConfig.DNSSearch) > 0 {
   489  		dnsSearch = container.hostConfig.DNSSearch
   490  	} else if len(container.daemon.configStore.DNSSearch) > 0 {
   491  		dnsSearch = container.daemon.configStore.DNSSearch
   492  	}
   493  
   494  	for _, ds := range dnsSearch {
   495  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
   496  	}
   497  
   498  	if len(container.hostConfig.DNSOptions) > 0 {
   499  		dnsOptions = container.hostConfig.DNSOptions
   500  	} else if len(container.daemon.configStore.DNSOptions) > 0 {
   501  		dnsOptions = container.daemon.configStore.DNSOptions
   502  	}
   503  
   504  	for _, ds := range dnsOptions {
   505  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
   506  	}
   507  
   508  	if container.NetworkSettings.SecondaryIPAddresses != nil {
   509  		name := container.Config.Hostname
   510  		if container.Config.Domainname != "" {
   511  			name = name + "." + container.Config.Domainname
   512  		}
   513  
   514  		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
   515  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
   516  		}
   517  	}
   518  
   519  	for _, extraHost := range container.hostConfig.ExtraHosts {
   520  		// allow IPv6 addresses in extra hosts; only split on first ":"
   521  		parts := strings.SplitN(extraHost, ":", 2)
   522  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
   523  	}
   524  
   525  	// Link feature is supported only for the default bridge network.
   526  	// return if this call to build join options is not for default bridge network
   527  	if n.Name() != "bridge" {
   528  		return sboxOptions, nil
   529  	}
   530  
   531  	ep, _ := container.getEndpointInNetwork(n)
   532  	if ep == nil {
   533  		return sboxOptions, nil
   534  	}
   535  
   536  	var childEndpoints, parentEndpoints []string
   537  
   538  	children, err := container.daemon.children(container.Name)
   539  	if err != nil {
   540  		return nil, err
   541  	}
   542  
   543  	for linkAlias, child := range children {
   544  		if !isLinkable(child) {
   545  			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
   546  		}
   547  		_, alias := path.Split(linkAlias)
   548  		// allow access to the linked container via the alias, real name, and container hostname
   549  		aliasList := alias + " " + child.Config.Hostname
   550  		// only add the name if alias isn't equal to the name
   551  		if alias != child.Name[1:] {
   552  			aliasList = aliasList + " " + child.Name[1:]
   553  		}
   554  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress))
   555  		cEndpoint, _ := child.getEndpointInNetwork(n)
   556  		if cEndpoint != nil && cEndpoint.ID() != "" {
   557  			childEndpoints = append(childEndpoints, cEndpoint.ID())
   558  		}
   559  	}
   560  
   561  	bridgeSettings := container.NetworkSettings.Networks["bridge"]
   562  	refs := container.daemon.containerGraph().RefPaths(container.ID)
   563  	for _, ref := range refs {
   564  		if ref.ParentID == "0" {
   565  			continue
   566  		}
   567  
   568  		c, err := container.daemon.Get(ref.ParentID)
   569  		if err != nil {
   570  			logrus.Error(err)
   571  		}
   572  
   573  		if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() {
   574  			logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, bridgeSettings.IPAddress)
   575  			sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, bridgeSettings.IPAddress))
   576  			if ep.ID() != "" {
   577  				parentEndpoints = append(parentEndpoints, ep.ID())
   578  			}
   579  		}
   580  	}
   581  
   582  	linkOptions := options.Generic{
   583  		netlabel.GenericData: options.Generic{
   584  			"ParentEndpoints": parentEndpoints,
   585  			"ChildEndpoints":  childEndpoints,
   586  		},
   587  	}
   588  
   589  	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
   590  
   591  	return sboxOptions, nil
   592  }
   593  
   594  func isLinkable(child *Container) bool {
   595  	// A container is linkable only if it belongs to the default network
   596  	_, ok := child.NetworkSettings.Networks["bridge"]
   597  	return ok
   598  }
   599  
   600  func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
   601  	endpointName := strings.TrimPrefix(container.Name, "/")
   602  	return n.EndpointByName(endpointName)
   603  }
   604  
   605  func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
   606  	if ep == nil {
   607  		return nil, derr.ErrorCodeEmptyEndpoint
   608  	}
   609  
   610  	if networkSettings == nil {
   611  		return nil, derr.ErrorCodeEmptyNetwork
   612  	}
   613  
   614  	driverInfo, err := ep.DriverInfo()
   615  	if err != nil {
   616  		return nil, err
   617  	}
   618  
   619  	if driverInfo == nil {
   620  		// It is not an error for epInfo to be nil
   621  		return networkSettings, nil
   622  	}
   623  
   624  	networkSettings.Ports = nat.PortMap{}
   625  
   626  	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
   627  		if exposedPorts, ok := expData.([]types.TransportPort); ok {
   628  			for _, tp := range exposedPorts {
   629  				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
   630  				if err != nil {
   631  					return nil, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
   632  				}
   633  				networkSettings.Ports[natPort] = nil
   634  			}
   635  		}
   636  	}
   637  
   638  	mapData, ok := driverInfo[netlabel.PortMap]
   639  	if !ok {
   640  		return networkSettings, nil
   641  	}
   642  
   643  	if portMapping, ok := mapData.([]types.PortBinding); ok {
   644  		for _, pp := range portMapping {
   645  			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
   646  			if err != nil {
   647  				return nil, err
   648  			}
   649  			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
   650  			networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
   651  		}
   652  	}
   653  
   654  	return networkSettings, nil
   655  }
   656  
   657  func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
   658  	if ep == nil {
   659  		return nil, derr.ErrorCodeEmptyEndpoint
   660  	}
   661  
   662  	if networkSettings == nil {
   663  		return nil, derr.ErrorCodeEmptyNetwork
   664  	}
   665  
   666  	epInfo := ep.Info()
   667  	if epInfo == nil {
   668  		// It is not an error to get an empty endpoint info
   669  		return networkSettings, nil
   670  	}
   671  
   672  	if _, ok := networkSettings.Networks[n.Name()]; !ok {
   673  		networkSettings.Networks[n.Name()] = new(network.EndpointSettings)
   674  	}
   675  	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
   676  
   677  	iface := epInfo.Iface()
   678  	if iface == nil {
   679  		return networkSettings, nil
   680  	}
   681  
   682  	if iface.Address() != nil {
   683  		ones, _ := iface.Address().Mask.Size()
   684  		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
   685  		networkSettings.Networks[n.Name()].IPPrefixLen = ones
   686  	}
   687  
   688  	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
   689  		onesv6, _ := iface.AddressIPv6().Mask.Size()
   690  		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
   691  		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
   692  	}
   693  
   694  	driverInfo, err := ep.DriverInfo()
   695  	if err != nil {
   696  		return nil, err
   697  	}
   698  
   699  	if driverInfo == nil {
   700  		// It is not an error for epInfo to be nil
   701  		return networkSettings, nil
   702  	}
   703  	if mac, ok := driverInfo[netlabel.MacAddress]; ok {
   704  		networkSettings.Networks[n.Name()].MacAddress = mac.(net.HardwareAddr).String()
   705  	}
   706  
   707  	return networkSettings, nil
   708  }
   709  
   710  func (container *Container) updateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
   711  	epInfo := ep.Info()
   712  	if epInfo == nil {
   713  		// It is not an error to get an empty endpoint info
   714  		return nil
   715  	}
   716  	container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
   717  	if epInfo.GatewayIPv6().To16() != nil {
   718  		container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
   719  	}
   720  
   721  	return nil
   722  }
   723  
   724  func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
   725  	if container.NetworkSettings == nil {
   726  		container.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)}
   727  	}
   728  
   729  	for s := range container.NetworkSettings.Networks {
   730  		sn, err := container.daemon.FindNetwork(s)
   731  		if err != nil {
   732  			continue
   733  		}
   734  
   735  		if sn.Name() == n.Name() {
   736  			// Avoid duplicate config
   737  			return nil
   738  		}
   739  		if !runconfig.NetworkMode(sn.Type()).IsPrivate() ||
   740  			!runconfig.NetworkMode(n.Type()).IsPrivate() {
   741  			return runconfig.ErrConflictSharedNetwork
   742  		}
   743  		if runconfig.NetworkMode(sn.Name()).IsNone() ||
   744  			runconfig.NetworkMode(n.Name()).IsNone() {
   745  			return runconfig.ErrConflictNoNetwork
   746  		}
   747  	}
   748  	container.NetworkSettings.Networks[n.Name()] = new(network.EndpointSettings)
   749  
   750  	return nil
   751  }
   752  
   753  func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
   754  	networkSettings, err := container.buildPortMapInfo(ep, container.NetworkSettings)
   755  	if err != nil {
   756  		return err
   757  	}
   758  
   759  	networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings)
   760  	if err != nil {
   761  		return err
   762  	}
   763  
   764  	if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") {
   765  		networkSettings.Bridge = container.daemon.configStore.Bridge.Iface
   766  	}
   767  
   768  	return nil
   769  }
   770  
   771  func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
   772  	container.NetworkSettings.SandboxID = sb.ID()
   773  	container.NetworkSettings.SandboxKey = sb.Key()
   774  	return nil
   775  }
   776  
   777  // UpdateNetwork is used to update the container's network (e.g. when linked containers
   778  // get removed/unlinked).
   779  func (container *Container) updateNetwork() error {
   780  	ctrl := container.daemon.netController
   781  	sid := container.NetworkSettings.SandboxID
   782  
   783  	sb, err := ctrl.SandboxByID(sid)
   784  	if err != nil {
   785  		return derr.ErrorCodeNoSandbox.WithArgs(sid, err)
   786  	}
   787  
   788  	// Find if container is connected to the default bridge network
   789  	var n libnetwork.Network
   790  	for name := range container.NetworkSettings.Networks {
   791  		sn, err := container.daemon.FindNetwork(name)
   792  		if err != nil {
   793  			continue
   794  		}
   795  		if sn.Name() == "bridge" {
   796  			n = sn
   797  			break
   798  		}
   799  	}
   800  
   801  	if n == nil {
   802  		// Not connected to the default bridge network; Nothing to do
   803  		return nil
   804  	}
   805  
   806  	options, err := container.buildSandboxOptions(n)
   807  	if err != nil {
   808  		return derr.ErrorCodeNetworkUpdate.WithArgs(err)
   809  	}
   810  
   811  	if err := sb.Refresh(options...); err != nil {
   812  		return derr.ErrorCodeNetworkRefresh.WithArgs(sid, err)
   813  	}
   814  
   815  	return nil
   816  }
   817  
   818  func (container *Container) buildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
   819  	var (
   820  		portSpecs     = make(nat.PortSet)
   821  		bindings      = make(nat.PortMap)
   822  		pbList        []types.PortBinding
   823  		exposeList    []types.TransportPort
   824  		createOptions []libnetwork.EndpointOption
   825  	)
   826  
   827  	if container.Config.ExposedPorts != nil {
   828  		portSpecs = container.Config.ExposedPorts
   829  	}
   830  
   831  	if container.hostConfig.PortBindings != nil {
   832  		for p, b := range container.hostConfig.PortBindings {
   833  			bindings[p] = []nat.PortBinding{}
   834  			for _, bb := range b {
   835  				bindings[p] = append(bindings[p], nat.PortBinding{
   836  					HostIP:   bb.HostIP,
   837  					HostPort: bb.HostPort,
   838  				})
   839  			}
   840  		}
   841  	}
   842  
   843  	ports := make([]nat.Port, len(portSpecs))
   844  	var i int
   845  	for p := range portSpecs {
   846  		ports[i] = p
   847  		i++
   848  	}
   849  	nat.SortPortMap(ports, bindings)
   850  	for _, port := range ports {
   851  		expose := types.TransportPort{}
   852  		expose.Proto = types.ParseProtocol(port.Proto())
   853  		expose.Port = uint16(port.Int())
   854  		exposeList = append(exposeList, expose)
   855  
   856  		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
   857  		binding := bindings[port]
   858  		for i := 0; i < len(binding); i++ {
   859  			pbCopy := pb.GetCopy()
   860  			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
   861  			var portStart, portEnd int
   862  			if err == nil {
   863  				portStart, portEnd, err = newP.Range()
   864  			}
   865  			if err != nil {
   866  				return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err)
   867  			}
   868  			pbCopy.HostPort = uint16(portStart)
   869  			pbCopy.HostPortEnd = uint16(portEnd)
   870  			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
   871  			pbList = append(pbList, pbCopy)
   872  		}
   873  
   874  		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
   875  			pbList = append(pbList, pb)
   876  		}
   877  	}
   878  
   879  	createOptions = append(createOptions,
   880  		libnetwork.CreateOptionPortMapping(pbList),
   881  		libnetwork.CreateOptionExposedPorts(exposeList))
   882  
   883  	if container.Config.MacAddress != "" {
   884  		mac, err := net.ParseMAC(container.Config.MacAddress)
   885  		if err != nil {
   886  			return nil, err
   887  		}
   888  
   889  		genericOption := options.Generic{
   890  			netlabel.MacAddress: mac,
   891  		}
   892  
   893  		createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
   894  	}
   895  
   896  	if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint {
   897  		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
   898  	}
   899  
   900  	return createOptions, nil
   901  }
   902  
   903  func createNetwork(controller libnetwork.NetworkController, dnet string, driver string) (libnetwork.Network, error) {
   904  	createOptions := []libnetwork.NetworkOption{}
   905  	genericOption := options.Generic{}
   906  
   907  	// Bridge driver is special due to legacy reasons
   908  	if runconfig.NetworkMode(driver).IsBridge() {
   909  		genericOption[netlabel.GenericData] = map[string]string{
   910  			bridge.BridgeName: dnet,
   911  		}
   912  		networkOption := libnetwork.NetworkOptionGeneric(genericOption)
   913  		createOptions = append(createOptions, networkOption)
   914  	}
   915  
   916  	return controller.NewNetwork(driver, dnet, createOptions...)
   917  }
   918  
   919  func (container *Container) allocateNetwork() error {
   920  	updateSettings := false
   921  	if len(container.NetworkSettings.Networks) == 0 {
   922  		mode := container.hostConfig.NetworkMode
   923  		controller := container.daemon.netController
   924  		if container.Config.NetworkDisabled || mode.IsContainer() {
   925  			return nil
   926  		}
   927  
   928  		networkName := mode.NetworkName()
   929  		if mode.IsDefault() {
   930  			networkName = controller.Config().Daemon.DefaultNetwork
   931  		}
   932  		container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   933  		container.NetworkSettings.Networks[networkName] = new(network.EndpointSettings)
   934  		updateSettings = true
   935  	}
   936  
   937  	for n := range container.NetworkSettings.Networks {
   938  		if err := container.connectToNetwork(n, updateSettings); err != nil {
   939  			return err
   940  		}
   941  	}
   942  
   943  	return container.writeHostConfig()
   944  }
   945  
   946  // ConnectToNetwork connects a container to a netork
   947  func (container *Container) ConnectToNetwork(idOrName string) error {
   948  	if !container.Running {
   949  		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
   950  	}
   951  	return container.connectToNetwork(idOrName, true)
   952  }
   953  
   954  func (container *Container) connectToNetwork(idOrName string, updateSettings bool) error {
   955  	var err error
   956  
   957  	if container.hostConfig.NetworkMode.IsContainer() {
   958  		return runconfig.ErrConflictSharedNetwork
   959  	}
   960  
   961  	if runconfig.NetworkMode(idOrName).IsBridge() &&
   962  		container.daemon.configStore.DisableBridge {
   963  		container.Config.NetworkDisabled = true
   964  		return nil
   965  	}
   966  
   967  	controller := container.daemon.netController
   968  
   969  	n, err := container.daemon.FindNetwork(idOrName)
   970  	if err != nil {
   971  		return err
   972  	}
   973  
   974  	if updateSettings {
   975  		if err := container.updateNetworkSettings(n); err != nil {
   976  			return err
   977  		}
   978  	}
   979  
   980  	ep, err := container.getEndpointInNetwork(n)
   981  	if err == nil {
   982  		return fmt.Errorf("container already connected to network %s", idOrName)
   983  	}
   984  
   985  	if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
   986  		return err
   987  	}
   988  
   989  	createOptions, err := container.buildCreateEndpointOptions(n)
   990  	if err != nil {
   991  		return err
   992  	}
   993  
   994  	endpointName := strings.TrimPrefix(container.Name, "/")
   995  	ep, err = n.CreateEndpoint(endpointName, createOptions...)
   996  	if err != nil {
   997  		return err
   998  	}
   999  	defer func() {
  1000  		if err != nil {
  1001  			if e := ep.Delete(); e != nil {
  1002  				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
  1003  			}
  1004  		}
  1005  	}()
  1006  
  1007  	if err := container.updateEndpointNetworkSettings(n, ep); err != nil {
  1008  		return err
  1009  	}
  1010  
  1011  	var sb libnetwork.Sandbox
  1012  	controller.WalkSandboxes(func(s libnetwork.Sandbox) bool {
  1013  		if s.ContainerID() == container.ID {
  1014  			sb = s
  1015  			return true
  1016  		}
  1017  		return false
  1018  	})
  1019  	if sb == nil {
  1020  		options, err := container.buildSandboxOptions(n)
  1021  		if err != nil {
  1022  			return err
  1023  		}
  1024  		sb, err = controller.NewSandbox(container.ID, options...)
  1025  		if err != nil {
  1026  			return err
  1027  		}
  1028  
  1029  		container.updateSandboxNetworkSettings(sb)
  1030  	}
  1031  
  1032  	if err := ep.Join(sb); err != nil {
  1033  		return err
  1034  	}
  1035  
  1036  	if err := container.updateJoinInfo(n, ep); err != nil {
  1037  		return derr.ErrorCodeJoinInfo.WithArgs(err)
  1038  	}
  1039  
  1040  	return nil
  1041  }
  1042  
  1043  func (container *Container) initializeNetworking() error {
  1044  	var err error
  1045  
  1046  	if container.hostConfig.NetworkMode.IsContainer() {
  1047  		// we need to get the hosts files from the container to join
  1048  		nc, err := container.getNetworkedContainer()
  1049  		if err != nil {
  1050  			return err
  1051  		}
  1052  		container.HostnamePath = nc.HostnamePath
  1053  		container.HostsPath = nc.HostsPath
  1054  		container.ResolvConfPath = nc.ResolvConfPath
  1055  		container.Config.Hostname = nc.Config.Hostname
  1056  		container.Config.Domainname = nc.Config.Domainname
  1057  		return nil
  1058  	}
  1059  
  1060  	if container.hostConfig.NetworkMode.IsHost() {
  1061  		container.Config.Hostname, err = os.Hostname()
  1062  		if err != nil {
  1063  			return err
  1064  		}
  1065  
  1066  		parts := strings.SplitN(container.Config.Hostname, ".", 2)
  1067  		if len(parts) > 1 {
  1068  			container.Config.Hostname = parts[0]
  1069  			container.Config.Domainname = parts[1]
  1070  		}
  1071  
  1072  	}
  1073  
  1074  	if err := container.allocateNetwork(); err != nil {
  1075  		return err
  1076  	}
  1077  
  1078  	return container.buildHostnameFile()
  1079  }
  1080  
  1081  // called from the libcontainer pre-start hook to set the network
  1082  // namespace configuration linkage to the libnetwork "sandbox" entity
  1083  func (container *Container) setNetworkNamespaceKey(pid int) error {
  1084  	path := fmt.Sprintf("/proc/%d/ns/net", pid)
  1085  	var sandbox libnetwork.Sandbox
  1086  	search := libnetwork.SandboxContainerWalker(&sandbox, container.ID)
  1087  	container.daemon.netController.WalkSandboxes(search)
  1088  	if sandbox == nil {
  1089  		return derr.ErrorCodeNoSandbox.WithArgs(container.ID)
  1090  	}
  1091  
  1092  	return sandbox.SetKey(path)
  1093  }
  1094  
  1095  func (container *Container) getIpcContainer() (*Container, error) {
  1096  	containerID := container.hostConfig.IpcMode.Container()
  1097  	c, err := container.daemon.Get(containerID)
  1098  	if err != nil {
  1099  		return nil, err
  1100  	}
  1101  	if !c.IsRunning() {
  1102  		return nil, derr.ErrorCodeIPCRunning
  1103  	}
  1104  	return c, nil
  1105  }
  1106  
  1107  func (container *Container) setupWorkingDirectory() error {
  1108  	if container.Config.WorkingDir != "" {
  1109  		container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
  1110  
  1111  		pth, err := container.GetResourcePath(container.Config.WorkingDir)
  1112  		if err != nil {
  1113  			return err
  1114  		}
  1115  
  1116  		pthInfo, err := os.Stat(pth)
  1117  		if err != nil {
  1118  			if !os.IsNotExist(err) {
  1119  				return err
  1120  			}
  1121  
  1122  			if err := system.MkdirAll(pth, 0755); err != nil {
  1123  				return err
  1124  			}
  1125  		}
  1126  		if pthInfo != nil && !pthInfo.IsDir() {
  1127  			return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
  1128  		}
  1129  	}
  1130  	return nil
  1131  }
  1132  
  1133  func (container *Container) getNetworkedContainer() (*Container, error) {
  1134  	parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2)
  1135  	switch parts[0] {
  1136  	case "container":
  1137  		if len(parts) != 2 {
  1138  			return nil, derr.ErrorCodeParseContainer
  1139  		}
  1140  		nc, err := container.daemon.Get(parts[1])
  1141  		if err != nil {
  1142  			return nil, err
  1143  		}
  1144  		if container == nc {
  1145  			return nil, derr.ErrorCodeJoinSelf
  1146  		}
  1147  		if !nc.IsRunning() {
  1148  			return nil, derr.ErrorCodeJoinRunning.WithArgs(parts[1])
  1149  		}
  1150  		return nc, nil
  1151  	default:
  1152  		return nil, derr.ErrorCodeModeNotContainer
  1153  	}
  1154  }
  1155  
  1156  func (container *Container) releaseNetwork() {
  1157  	if container.hostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
  1158  		return
  1159  	}
  1160  
  1161  	sid := container.NetworkSettings.SandboxID
  1162  	networks := container.NetworkSettings.Networks
  1163  	for n := range networks {
  1164  		networks[n] = &network.EndpointSettings{}
  1165  	}
  1166  
  1167  	container.NetworkSettings = &network.Settings{Networks: networks}
  1168  
  1169  	if sid == "" || len(networks) == 0 {
  1170  		return
  1171  	}
  1172  
  1173  	sb, err := container.daemon.netController.SandboxByID(sid)
  1174  	if err != nil {
  1175  		logrus.Errorf("error locating sandbox id %s: %v", sid, err)
  1176  		return
  1177  	}
  1178  
  1179  	if err := sb.Delete(); err != nil {
  1180  		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
  1181  	}
  1182  }
  1183  
  1184  // DisconnectFromNetwork disconnects a container from a network
  1185  func (container *Container) DisconnectFromNetwork(n libnetwork.Network) error {
  1186  	if !container.Running {
  1187  		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
  1188  	}
  1189  
  1190  	return container.disconnectFromNetwork(n)
  1191  }
  1192  
  1193  func (container *Container) disconnectFromNetwork(n libnetwork.Network) error {
  1194  	var (
  1195  		ep   libnetwork.Endpoint
  1196  		sbox libnetwork.Sandbox
  1197  	)
  1198  
  1199  	s := func(current libnetwork.Endpoint) bool {
  1200  		if sb := current.Info().Sandbox(); sb != nil {
  1201  			if sb.ContainerID() == container.ID {
  1202  				ep = current
  1203  				sbox = sb
  1204  				return true
  1205  			}
  1206  		}
  1207  		return false
  1208  	}
  1209  	n.WalkEndpoints(s)
  1210  
  1211  	if ep == nil {
  1212  		return fmt.Errorf("container %s is not connected to the network", container.ID)
  1213  	}
  1214  
  1215  	if err := ep.Leave(sbox); err != nil {
  1216  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
  1217  	}
  1218  
  1219  	if err := ep.Delete(); err != nil {
  1220  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
  1221  	}
  1222  
  1223  	delete(container.NetworkSettings.Networks, n.Name())
  1224  	return nil
  1225  }
  1226  
  1227  func (container *Container) unmountVolumes(forceSyscall bool) error {
  1228  	var volumeMounts []mountPoint
  1229  
  1230  	for _, mntPoint := range container.MountPoints {
  1231  		dest, err := container.GetResourcePath(mntPoint.Destination)
  1232  		if err != nil {
  1233  			return err
  1234  		}
  1235  
  1236  		volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume})
  1237  	}
  1238  
  1239  	for _, mnt := range container.networkMounts() {
  1240  		dest, err := container.GetResourcePath(mnt.Destination)
  1241  		if err != nil {
  1242  			return err
  1243  		}
  1244  
  1245  		volumeMounts = append(volumeMounts, mountPoint{Destination: dest})
  1246  	}
  1247  
  1248  	for _, volumeMount := range volumeMounts {
  1249  		if forceSyscall {
  1250  			syscall.Unmount(volumeMount.Destination, 0)
  1251  		}
  1252  
  1253  		if volumeMount.Volume != nil {
  1254  			if err := volumeMount.Volume.Unmount(); err != nil {
  1255  				return err
  1256  			}
  1257  		}
  1258  	}
  1259  
  1260  	return nil
  1261  }
  1262  
  1263  func (container *Container) networkMounts() []execdriver.Mount {
  1264  	var mounts []execdriver.Mount
  1265  	shared := container.hostConfig.NetworkMode.IsContainer()
  1266  	if container.ResolvConfPath != "" {
  1267  		if _, err := os.Stat(container.ResolvConfPath); err != nil {
  1268  			logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err)
  1269  		} else {
  1270  			label.Relabel(container.ResolvConfPath, container.MountLabel, shared)
  1271  			writable := !container.hostConfig.ReadonlyRootfs
  1272  			if m, exists := container.MountPoints["/etc/resolv.conf"]; exists {
  1273  				writable = m.RW
  1274  			}
  1275  			mounts = append(mounts, execdriver.Mount{
  1276  				Source:      container.ResolvConfPath,
  1277  				Destination: "/etc/resolv.conf",
  1278  				Writable:    writable,
  1279  				Private:     true,
  1280  			})
  1281  		}
  1282  	}
  1283  	if container.HostnamePath != "" {
  1284  		if _, err := os.Stat(container.HostnamePath); err != nil {
  1285  			logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err)
  1286  		} else {
  1287  			label.Relabel(container.HostnamePath, container.MountLabel, shared)
  1288  			writable := !container.hostConfig.ReadonlyRootfs
  1289  			if m, exists := container.MountPoints["/etc/hostname"]; exists {
  1290  				writable = m.RW
  1291  			}
  1292  			mounts = append(mounts, execdriver.Mount{
  1293  				Source:      container.HostnamePath,
  1294  				Destination: "/etc/hostname",
  1295  				Writable:    writable,
  1296  				Private:     true,
  1297  			})
  1298  		}
  1299  	}
  1300  	if container.HostsPath != "" {
  1301  		if _, err := os.Stat(container.HostsPath); err != nil {
  1302  			logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err)
  1303  		} else {
  1304  			label.Relabel(container.HostsPath, container.MountLabel, shared)
  1305  			writable := !container.hostConfig.ReadonlyRootfs
  1306  			if m, exists := container.MountPoints["/etc/hosts"]; exists {
  1307  				writable = m.RW
  1308  			}
  1309  			mounts = append(mounts, execdriver.Mount{
  1310  				Source:      container.HostsPath,
  1311  				Destination: "/etc/hosts",
  1312  				Writable:    writable,
  1313  				Private:     true,
  1314  			})
  1315  		}
  1316  	}
  1317  	return mounts
  1318  }
  1319  
  1320  func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
  1321  	container.MountPoints[destination] = &mountPoint{
  1322  		Name:        name,
  1323  		Source:      source,
  1324  		Destination: destination,
  1325  		RW:          rw,
  1326  	}
  1327  }
  1328  
  1329  func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
  1330  	container.MountPoints[destination] = &mountPoint{
  1331  		Name:        name,
  1332  		Driver:      volume.DefaultDriverName,
  1333  		Destination: destination,
  1334  		RW:          rw,
  1335  	}
  1336  }
  1337  
  1338  func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
  1339  	container.MountPoints[destination] = &mountPoint{
  1340  		Name:        vol.Name(),
  1341  		Driver:      vol.DriverName(),
  1342  		Destination: destination,
  1343  		RW:          rw,
  1344  		Volume:      vol,
  1345  	}
  1346  }
  1347  
  1348  func (container *Container) isDestinationMounted(destination string) bool {
  1349  	return container.MountPoints[destination] != nil
  1350  }
  1351  
  1352  func (container *Container) prepareMountPoints() error {
  1353  	for _, config := range container.MountPoints {
  1354  		if len(config.Driver) > 0 {
  1355  			v, err := container.daemon.createVolume(config.Name, config.Driver, nil)
  1356  			if err != nil {
  1357  				return err
  1358  			}
  1359  			config.Volume = v
  1360  		}
  1361  	}
  1362  	return nil
  1363  }
  1364  
  1365  func (container *Container) removeMountPoints(rm bool) error {
  1366  	var rmErrors []string
  1367  	for _, m := range container.MountPoints {
  1368  		if m.Volume == nil {
  1369  			continue
  1370  		}
  1371  		container.daemon.volumes.Decrement(m.Volume)
  1372  		if rm {
  1373  			err := container.daemon.volumes.Remove(m.Volume)
  1374  			// ErrVolumeInUse is ignored because having this
  1375  			// volume being referenced by othe container is
  1376  			// not an error, but an implementation detail.
  1377  			// This prevents docker from logging "ERROR: Volume in use"
  1378  			// where there is another container using the volume.
  1379  			if err != nil && err != store.ErrVolumeInUse {
  1380  				rmErrors = append(rmErrors, err.Error())
  1381  			}
  1382  		}
  1383  	}
  1384  	if len(rmErrors) > 0 {
  1385  		return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n"))
  1386  	}
  1387  	return nil
  1388  }
  1389  
  1390  func (container *Container) shmPath() (string, error) {
  1391  	return container.getRootResourcePath("shm")
  1392  }
  1393  func (container *Container) mqueuePath() (string, error) {
  1394  	return container.getRootResourcePath("mqueue")
  1395  }
  1396  
  1397  func (container *Container) hasMountFor(path string) bool {
  1398  	_, exists := container.MountPoints[path]
  1399  	return exists
  1400  }
  1401  
  1402  func (container *Container) setupIpcDirs() error {
  1403  	rootUID, rootGID := container.daemon.GetRemappedUIDGID()
  1404  	if !container.hasMountFor("/dev/shm") {
  1405  		shmPath, err := container.shmPath()
  1406  		if err != nil {
  1407  			return err
  1408  		}
  1409  
  1410  		if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil {
  1411  			return err
  1412  		}
  1413  
  1414  		if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("mode=1777,size=65536k", container.getMountLabel())); err != nil {
  1415  			return fmt.Errorf("mounting shm tmpfs: %s", err)
  1416  		}
  1417  		if err := os.Chown(shmPath, rootUID, rootGID); err != nil {
  1418  			return err
  1419  		}
  1420  	}
  1421  
  1422  	if !container.hasMountFor("/dev/mqueue") {
  1423  		mqueuePath, err := container.mqueuePath()
  1424  		if err != nil {
  1425  			return err
  1426  		}
  1427  
  1428  		if err := idtools.MkdirAllAs(mqueuePath, 0700, rootUID, rootGID); err != nil {
  1429  			return err
  1430  		}
  1431  
  1432  		if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
  1433  			return fmt.Errorf("mounting mqueue mqueue : %s", err)
  1434  		}
  1435  		if err := os.Chown(mqueuePath, rootUID, rootGID); err != nil {
  1436  			return err
  1437  		}
  1438  	}
  1439  
  1440  	return nil
  1441  }
  1442  
  1443  func (container *Container) unmountIpcMounts() error {
  1444  	if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
  1445  		return nil
  1446  	}
  1447  
  1448  	var errors []string
  1449  
  1450  	if !container.hasMountFor("/dev/shm") {
  1451  		shmPath, err := container.shmPath()
  1452  		if err != nil {
  1453  			logrus.Error(err)
  1454  			errors = append(errors, err.Error())
  1455  		} else {
  1456  			if err := detachMounted(shmPath); err != nil {
  1457  				logrus.Errorf("failed to umount %s: %v", shmPath, err)
  1458  				errors = append(errors, err.Error())
  1459  			}
  1460  
  1461  		}
  1462  	}
  1463  
  1464  	if !container.hasMountFor("/dev/mqueue") {
  1465  		mqueuePath, err := container.mqueuePath()
  1466  		if err != nil {
  1467  			logrus.Error(err)
  1468  			errors = append(errors, err.Error())
  1469  		} else {
  1470  			if err := detachMounted(mqueuePath); err != nil {
  1471  				logrus.Errorf("failed to umount %s: %v", mqueuePath, err)
  1472  				errors = append(errors, err.Error())
  1473  			}
  1474  		}
  1475  	}
  1476  
  1477  	if len(errors) > 0 {
  1478  		return fmt.Errorf("failed to cleanup ipc mounts:\n%v", strings.Join(errors, "\n"))
  1479  	}
  1480  
  1481  	return nil
  1482  }
  1483  
  1484  func (container *Container) ipcMounts() []execdriver.Mount {
  1485  	var mounts []execdriver.Mount
  1486  
  1487  	if !container.hasMountFor("/dev/shm") {
  1488  		label.SetFileLabel(container.ShmPath, container.MountLabel)
  1489  		mounts = append(mounts, execdriver.Mount{
  1490  			Source:      container.ShmPath,
  1491  			Destination: "/dev/shm",
  1492  			Writable:    true,
  1493  			Private:     true,
  1494  		})
  1495  	}
  1496  
  1497  	if !container.hasMountFor("/dev/mqueue") {
  1498  		label.SetFileLabel(container.MqueuePath, container.MountLabel)
  1499  		mounts = append(mounts, execdriver.Mount{
  1500  			Source:      container.MqueuePath,
  1501  			Destination: "/dev/mqueue",
  1502  			Writable:    true,
  1503  			Private:     true,
  1504  		})
  1505  	}
  1506  	return mounts
  1507  }
  1508  
  1509  func detachMounted(path string) error {
  1510  	return syscall.Unmount(path, syscall.MNT_DETACH)
  1511  }