github.com/brahmaroutu/docker@v1.2.1-0.20160809185609-eb28dde01f16/daemon/daemon_unix.go (about)

     1  // +build linux freebsd
     2  
     3  package daemon
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"runtime/debug"
    14  	"strconv"
    15  	"strings"
    16  	"syscall"
    17  
    18  	"github.com/Sirupsen/logrus"
    19  	"github.com/docker/docker/container"
    20  	"github.com/docker/docker/image"
    21  	"github.com/docker/docker/pkg/idtools"
    22  	"github.com/docker/docker/pkg/parsers"
    23  	"github.com/docker/docker/pkg/parsers/kernel"
    24  	"github.com/docker/docker/pkg/sysinfo"
    25  	"github.com/docker/docker/runconfig"
    26  	runconfigopts "github.com/docker/docker/runconfig/opts"
    27  	"github.com/docker/engine-api/types"
    28  	"github.com/docker/engine-api/types/blkiodev"
    29  	pblkiodev "github.com/docker/engine-api/types/blkiodev"
    30  	containertypes "github.com/docker/engine-api/types/container"
    31  	"github.com/docker/libnetwork"
    32  	nwconfig "github.com/docker/libnetwork/config"
    33  	"github.com/docker/libnetwork/drivers/bridge"
    34  	"github.com/docker/libnetwork/netlabel"
    35  	"github.com/docker/libnetwork/netutils"
    36  	"github.com/docker/libnetwork/options"
    37  	lntypes "github.com/docker/libnetwork/types"
    38  	"github.com/golang/protobuf/ptypes"
    39  	"github.com/opencontainers/runc/libcontainer/label"
    40  	"github.com/opencontainers/runc/libcontainer/user"
    41  	"github.com/opencontainers/specs/specs-go"
    42  )
    43  
    44  const (
    45  	// See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
    46  	linuxMinCPUShares = 2
    47  	linuxMaxCPUShares = 262144
    48  	platformSupported = true
    49  	// It's not kernel limit, we want this 4M limit to supply a reasonable functional container
    50  	linuxMinMemory = 4194304
    51  	// constants for remapped root settings
    52  	defaultIDSpecifier string = "default"
    53  	defaultRemappedID  string = "dockremap"
    54  
    55  	// constant for cgroup drivers
    56  	cgroupFsDriver      = "cgroupfs"
    57  	cgroupSystemdDriver = "systemd"
    58  )
    59  
    60  func getMemoryResources(config containertypes.Resources) *specs.Memory {
    61  	memory := specs.Memory{}
    62  
    63  	if config.Memory > 0 {
    64  		limit := uint64(config.Memory)
    65  		memory.Limit = &limit
    66  	}
    67  
    68  	if config.MemoryReservation > 0 {
    69  		reservation := uint64(config.MemoryReservation)
    70  		memory.Reservation = &reservation
    71  	}
    72  
    73  	if config.MemorySwap != 0 {
    74  		swap := uint64(config.MemorySwap)
    75  		memory.Swap = &swap
    76  	}
    77  
    78  	if config.MemorySwappiness != nil {
    79  		swappiness := uint64(*config.MemorySwappiness)
    80  		memory.Swappiness = &swappiness
    81  	}
    82  
    83  	if config.KernelMemory != 0 {
    84  		kernelMemory := uint64(config.KernelMemory)
    85  		memory.Kernel = &kernelMemory
    86  	}
    87  
    88  	return &memory
    89  }
    90  
    91  func getCPUResources(config containertypes.Resources) *specs.CPU {
    92  	cpu := specs.CPU{}
    93  
    94  	if config.CPUShares != 0 {
    95  		shares := uint64(config.CPUShares)
    96  		cpu.Shares = &shares
    97  	}
    98  
    99  	if config.CpusetCpus != "" {
   100  		cpuset := config.CpusetCpus
   101  		cpu.Cpus = &cpuset
   102  	}
   103  
   104  	if config.CpusetMems != "" {
   105  		cpuset := config.CpusetMems
   106  		cpu.Mems = &cpuset
   107  	}
   108  
   109  	if config.CPUPeriod != 0 {
   110  		period := uint64(config.CPUPeriod)
   111  		cpu.Period = &period
   112  	}
   113  
   114  	if config.CPUQuota != 0 {
   115  		quota := uint64(config.CPUQuota)
   116  		cpu.Quota = &quota
   117  	}
   118  
   119  	return &cpu
   120  }
   121  
   122  func getBlkioWeightDevices(config containertypes.Resources) ([]specs.WeightDevice, error) {
   123  	var stat syscall.Stat_t
   124  	var blkioWeightDevices []specs.WeightDevice
   125  
   126  	for _, weightDevice := range config.BlkioWeightDevice {
   127  		if err := syscall.Stat(weightDevice.Path, &stat); err != nil {
   128  			return nil, err
   129  		}
   130  		weight := weightDevice.Weight
   131  		d := specs.WeightDevice{Weight: &weight}
   132  		d.Major = int64(stat.Rdev / 256)
   133  		d.Minor = int64(stat.Rdev % 256)
   134  		blkioWeightDevices = append(blkioWeightDevices, d)
   135  	}
   136  
   137  	return blkioWeightDevices, nil
   138  }
   139  
   140  func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
   141  	var (
   142  		labelOpts []string
   143  		err       error
   144  	)
   145  
   146  	for _, opt := range config.SecurityOpt {
   147  		if opt == "no-new-privileges" {
   148  			container.NoNewPrivileges = true
   149  		} else {
   150  			var con []string
   151  			if strings.Contains(opt, "=") {
   152  				con = strings.SplitN(opt, "=", 2)
   153  			} else if strings.Contains(opt, ":") {
   154  				con = strings.SplitN(opt, ":", 2)
   155  				logrus.Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 1.13, use `=` instead.")
   156  			}
   157  
   158  			if len(con) != 2 {
   159  				return fmt.Errorf("Invalid --security-opt 1: %q", opt)
   160  			}
   161  
   162  			switch con[0] {
   163  			case "label":
   164  				labelOpts = append(labelOpts, con[1])
   165  			case "apparmor":
   166  				container.AppArmorProfile = con[1]
   167  			case "seccomp":
   168  				container.SeccompProfile = con[1]
   169  			default:
   170  				return fmt.Errorf("Invalid --security-opt 2: %q", opt)
   171  			}
   172  		}
   173  	}
   174  
   175  	container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
   176  	return err
   177  }
   178  
   179  func getBlkioThrottleDevices(devs []*blkiodev.ThrottleDevice) ([]specs.ThrottleDevice, error) {
   180  	var throttleDevices []specs.ThrottleDevice
   181  	var stat syscall.Stat_t
   182  
   183  	for _, d := range devs {
   184  		if err := syscall.Stat(d.Path, &stat); err != nil {
   185  			return nil, err
   186  		}
   187  		rate := d.Rate
   188  		d := specs.ThrottleDevice{Rate: &rate}
   189  		d.Major = int64(stat.Rdev / 256)
   190  		d.Minor = int64(stat.Rdev % 256)
   191  		throttleDevices = append(throttleDevices, d)
   192  	}
   193  
   194  	return throttleDevices, nil
   195  }
   196  
   197  func checkKernel() error {
   198  	// Check for unsupported kernel versions
   199  	// FIXME: it would be cleaner to not test for specific versions, but rather
   200  	// test for specific functionalities.
   201  	// Unfortunately we can't test for the feature "does not cause a kernel panic"
   202  	// without actually causing a kernel panic, so we need this workaround until
   203  	// the circumstances of pre-3.10 crashes are clearer.
   204  	// For details see https://github.com/docker/docker/issues/407
   205  	// Docker 1.11 and above doesn't actually run on kernels older than 3.4,
   206  	// due to containerd-shim usage of PR_SET_CHILD_SUBREAPER (introduced in 3.4).
   207  	if !kernel.CheckKernelVersion(3, 10, 0) {
   208  		v, _ := kernel.GetKernelVersion()
   209  		if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
   210  			logrus.Fatalf("Your Linux kernel version %s is not supported for running docker. Please upgrade your kernel to 3.10.0 or newer.", v.String())
   211  		}
   212  	}
   213  	return nil
   214  }
   215  
   216  // adaptContainerSettings is called during container creation to modify any
   217  // settings necessary in the HostConfig structure.
   218  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
   219  	if adjustCPUShares && hostConfig.CPUShares > 0 {
   220  		// Handle unsupported CPUShares
   221  		if hostConfig.CPUShares < linuxMinCPUShares {
   222  			logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares)
   223  			hostConfig.CPUShares = linuxMinCPUShares
   224  		} else if hostConfig.CPUShares > linuxMaxCPUShares {
   225  			logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares)
   226  			hostConfig.CPUShares = linuxMaxCPUShares
   227  		}
   228  	}
   229  	if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
   230  		// By default, MemorySwap is set to twice the size of Memory.
   231  		hostConfig.MemorySwap = hostConfig.Memory * 2
   232  	}
   233  	if hostConfig.ShmSize == 0 {
   234  		hostConfig.ShmSize = container.DefaultSHMSize
   235  	}
   236  	var err error
   237  	if hostConfig.SecurityOpt == nil {
   238  		hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode, hostConfig.Privileged)
   239  		if err != nil {
   240  			return err
   241  		}
   242  	}
   243  	if hostConfig.MemorySwappiness == nil {
   244  		defaultSwappiness := int64(-1)
   245  		hostConfig.MemorySwappiness = &defaultSwappiness
   246  	}
   247  	if hostConfig.OomKillDisable == nil {
   248  		defaultOomKillDisable := false
   249  		hostConfig.OomKillDisable = &defaultOomKillDisable
   250  	}
   251  
   252  	return nil
   253  }
   254  
   255  func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) {
   256  	warnings := []string{}
   257  
   258  	// memory subsystem checks and adjustments
   259  	if resources.Memory != 0 && resources.Memory < linuxMinMemory {
   260  		return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
   261  	}
   262  	if resources.Memory > 0 && !sysInfo.MemoryLimit {
   263  		warnings = append(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
   264  		logrus.Warn("Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
   265  		resources.Memory = 0
   266  		resources.MemorySwap = -1
   267  	}
   268  	if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit {
   269  		warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.")
   270  		logrus.Warn("Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
   271  		resources.MemorySwap = -1
   272  	}
   273  	if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory {
   274  		return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage")
   275  	}
   276  	if resources.Memory == 0 && resources.MemorySwap > 0 && !update {
   277  		return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage")
   278  	}
   279  	if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness {
   280  		warnings = append(warnings, "Your kernel does not support memory swappiness capabilities or the cgroup is not mounted. Memory swappiness discarded.")
   281  		logrus.Warn("Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded.")
   282  		resources.MemorySwappiness = nil
   283  	}
   284  	if resources.MemorySwappiness != nil {
   285  		swappiness := *resources.MemorySwappiness
   286  		if swappiness < -1 || swappiness > 100 {
   287  			return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100", swappiness)
   288  		}
   289  	}
   290  	if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
   291  		warnings = append(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
   292  		logrus.Warn("Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
   293  		resources.MemoryReservation = 0
   294  	}
   295  	if resources.MemoryReservation > 0 && resources.MemoryReservation < linuxMinMemory {
   296  		return warnings, fmt.Errorf("Minimum memory reservation allowed is 4MB")
   297  	}
   298  	if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation {
   299  		return warnings, fmt.Errorf("Minimum memory limit can not be less than memory reservation limit, see usage")
   300  	}
   301  	if resources.KernelMemory > 0 && !sysInfo.KernelMemory {
   302  		warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
   303  		logrus.Warn("Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
   304  		resources.KernelMemory = 0
   305  	}
   306  	if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory {
   307  		return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB")
   308  	}
   309  	if resources.KernelMemory > 0 && !kernel.CheckKernelVersion(4, 0, 0) {
   310  		warnings = append(warnings, "You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
   311  		logrus.Warn("You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
   312  	}
   313  	if resources.OomKillDisable != nil && !sysInfo.OomKillDisable {
   314  		// only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
   315  		// warning the caller if they already wanted the feature to be off
   316  		if *resources.OomKillDisable {
   317  			warnings = append(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
   318  			logrus.Warn("Your kernel does not support OomKillDisable. OomKillDisable discarded.")
   319  		}
   320  		resources.OomKillDisable = nil
   321  	}
   322  
   323  	if resources.PidsLimit != 0 && !sysInfo.PidsLimit {
   324  		warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
   325  		logrus.Warn("Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
   326  		resources.PidsLimit = 0
   327  	}
   328  
   329  	// cpu subsystem checks and adjustments
   330  	if resources.CPUShares > 0 && !sysInfo.CPUShares {
   331  		warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
   332  		logrus.Warn("Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
   333  		resources.CPUShares = 0
   334  	}
   335  	if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
   336  		warnings = append(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
   337  		logrus.Warn("Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
   338  		resources.CPUPeriod = 0
   339  	}
   340  	if resources.CPUPeriod != 0 && (resources.CPUPeriod < 1000 || resources.CPUPeriod > 1000000) {
   341  		return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
   342  	}
   343  	if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
   344  		warnings = append(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
   345  		logrus.Warn("Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
   346  		resources.CPUQuota = 0
   347  	}
   348  	if resources.CPUQuota > 0 && resources.CPUQuota < 1000 {
   349  		return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
   350  	}
   351  	if resources.CPUPercent > 0 {
   352  		warnings = append(warnings, "%s does not support CPU percent. Percent discarded.", runtime.GOOS)
   353  		logrus.Warnf("%s does not support CPU percent. Percent discarded.", runtime.GOOS)
   354  		resources.CPUPercent = 0
   355  	}
   356  
   357  	// cpuset subsystem checks and adjustments
   358  	if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset {
   359  		warnings = append(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.")
   360  		logrus.Warn("Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.")
   361  		resources.CpusetCpus = ""
   362  		resources.CpusetMems = ""
   363  	}
   364  	cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
   365  	if err != nil {
   366  		return warnings, fmt.Errorf("Invalid value %s for cpuset cpus", resources.CpusetCpus)
   367  	}
   368  	if !cpusAvailable {
   369  		return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s", resources.CpusetCpus, sysInfo.Cpus)
   370  	}
   371  	memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
   372  	if err != nil {
   373  		return warnings, fmt.Errorf("Invalid value %s for cpuset mems", resources.CpusetMems)
   374  	}
   375  	if !memsAvailable {
   376  		return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s", resources.CpusetMems, sysInfo.Mems)
   377  	}
   378  
   379  	// blkio subsystem checks and adjustments
   380  	if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
   381  		warnings = append(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
   382  		logrus.Warn("Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
   383  		resources.BlkioWeight = 0
   384  	}
   385  	if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
   386  		return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000")
   387  	}
   388  	if resources.IOMaximumBandwidth != 0 || resources.IOMaximumIOps != 0 {
   389  		return warnings, fmt.Errorf("Invalid QoS settings: %s does not support Maximum IO Bandwidth or Maximum IO IOps", runtime.GOOS)
   390  	}
   391  	if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
   392  		warnings = append(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
   393  		logrus.Warn("Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
   394  		resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
   395  	}
   396  	if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
   397  		warnings = append(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded.")
   398  		logrus.Warn("Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded")
   399  		resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
   400  	}
   401  	if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
   402  		warnings = append(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
   403  		logrus.Warn("Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
   404  		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
   405  	}
   406  	if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
   407  		warnings = append(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
   408  		logrus.Warn("Your kernel does not support IOPS Block I/O read limit in IO or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
   409  		resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
   410  	}
   411  	if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
   412  		warnings = append(warnings, "Your kernel does not support IOPS Block write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
   413  		logrus.Warn("Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
   414  		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
   415  	}
   416  
   417  	return warnings, nil
   418  }
   419  
   420  func (daemon *Daemon) getCgroupDriver() string {
   421  	cgroupDriver := cgroupFsDriver
   422  
   423  	if UsingSystemd(daemon.configStore) {
   424  		cgroupDriver = cgroupSystemdDriver
   425  	}
   426  	return cgroupDriver
   427  }
   428  
   429  // getCD gets the raw value of the native.cgroupdriver option, if set.
   430  func getCD(config *Config) string {
   431  	for _, option := range config.ExecOptions {
   432  		key, val, err := parsers.ParseKeyValueOpt(option)
   433  		if err != nil || !strings.EqualFold(key, "native.cgroupdriver") {
   434  			continue
   435  		}
   436  		return val
   437  	}
   438  	return ""
   439  }
   440  
   441  // VerifyCgroupDriver validates native.cgroupdriver
   442  func VerifyCgroupDriver(config *Config) error {
   443  	cd := getCD(config)
   444  	if cd == "" || cd == cgroupFsDriver || cd == cgroupSystemdDriver {
   445  		return nil
   446  	}
   447  	return fmt.Errorf("native.cgroupdriver option %s not supported", cd)
   448  }
   449  
   450  // UsingSystemd returns true if cli option includes native.cgroupdriver=systemd
   451  func UsingSystemd(config *Config) bool {
   452  	return getCD(config) == cgroupSystemdDriver
   453  }
   454  
   455  // verifyPlatformContainerSettings performs platform-specific validation of the
   456  // hostconfig and config structures.
   457  func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
   458  	warnings := []string{}
   459  	sysInfo := sysinfo.New(true)
   460  
   461  	warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config)
   462  	if err != nil {
   463  		return warnings, err
   464  	}
   465  
   466  	w, err := verifyContainerResources(&hostConfig.Resources, sysInfo, update)
   467  	if err != nil {
   468  		return warnings, err
   469  	}
   470  	warnings = append(warnings, w...)
   471  
   472  	if hostConfig.ShmSize < 0 {
   473  		return warnings, fmt.Errorf("SHM size can not be less than 0")
   474  	}
   475  
   476  	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
   477  		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000]", hostConfig.OomScoreAdj)
   478  	}
   479  
   480  	// ip-forwarding does not affect container with '--net=host' (or '--net=none')
   481  	if sysInfo.IPv4ForwardingDisabled && !(hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsNone()) {
   482  		warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
   483  		logrus.Warn("IPv4 forwarding is disabled. Networking will not work")
   484  	}
   485  	// check for various conflicting options with user namespaces
   486  	if daemon.configStore.RemappedRoot != "" && hostConfig.UsernsMode.IsPrivate() {
   487  		if hostConfig.Privileged {
   488  			return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces")
   489  		}
   490  		if hostConfig.NetworkMode.IsHost() {
   491  			return warnings, fmt.Errorf("Cannot share the host's network namespace when user namespaces are enabled")
   492  		}
   493  		if hostConfig.PidMode.IsHost() {
   494  			return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled")
   495  		}
   496  		if hostConfig.ReadonlyRootfs {
   497  			return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled")
   498  		}
   499  	}
   500  	if hostConfig.CgroupParent != "" && UsingSystemd(daemon.configStore) {
   501  		// CgroupParent for systemd cgroup should be named as "xxx.slice"
   502  		if len(hostConfig.CgroupParent) <= 6 || !strings.HasSuffix(hostConfig.CgroupParent, ".slice") {
   503  			return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
   504  		}
   505  	}
   506  	if hostConfig.Runtime == "" {
   507  		hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
   508  	}
   509  
   510  	if rt := daemon.configStore.GetRuntime(hostConfig.Runtime); rt == nil {
   511  		return warnings, fmt.Errorf("Unknown runtime specified %s", hostConfig.Runtime)
   512  	}
   513  
   514  	return warnings, nil
   515  }
   516  
   517  // platformReload update configuration with platform specific options
   518  func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
   519  	if config.IsValueSet("runtimes") {
   520  		daemon.configStore.Runtimes = config.Runtimes
   521  		// Always set the default one
   522  		daemon.configStore.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary}
   523  	}
   524  
   525  	if config.DefaultRuntime != "" {
   526  		daemon.configStore.DefaultRuntime = config.DefaultRuntime
   527  	}
   528  
   529  	// Update attributes
   530  	var runtimeList bytes.Buffer
   531  	for name, rt := range daemon.configStore.Runtimes {
   532  		if runtimeList.Len() > 0 {
   533  			runtimeList.WriteRune(' ')
   534  		}
   535  		runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt))
   536  	}
   537  
   538  	(*attributes)["runtimes"] = runtimeList.String()
   539  	(*attributes)["default-runtime"] = daemon.configStore.DefaultRuntime
   540  }
   541  
   542  // verifyDaemonSettings performs validation of daemon config struct
   543  func verifyDaemonSettings(config *Config) error {
   544  	// Check for mutually incompatible config options
   545  	if config.bridgeConfig.Iface != "" && config.bridgeConfig.IP != "" {
   546  		return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one")
   547  	}
   548  	if !config.bridgeConfig.EnableIPTables && !config.bridgeConfig.InterContainerCommunication {
   549  		return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true")
   550  	}
   551  	if !config.bridgeConfig.EnableIPTables && config.bridgeConfig.EnableIPMasq {
   552  		config.bridgeConfig.EnableIPMasq = false
   553  	}
   554  	if err := VerifyCgroupDriver(config); err != nil {
   555  		return err
   556  	}
   557  	if config.CgroupParent != "" && UsingSystemd(config) {
   558  		if len(config.CgroupParent) <= 6 || !strings.HasSuffix(config.CgroupParent, ".slice") {
   559  			return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
   560  		}
   561  	}
   562  
   563  	if config.DefaultRuntime == "" {
   564  		config.DefaultRuntime = stockRuntimeName
   565  	}
   566  	if config.Runtimes == nil {
   567  		config.Runtimes = make(map[string]types.Runtime)
   568  	}
   569  	stockRuntimeOpts := []string{}
   570  	if UsingSystemd(config) {
   571  		stockRuntimeOpts = append(stockRuntimeOpts, "--systemd-cgroup=true")
   572  	}
   573  	config.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary, Args: stockRuntimeOpts}
   574  
   575  	return nil
   576  }
   577  
   578  // checkSystem validates platform-specific requirements
   579  func checkSystem() error {
   580  	if os.Geteuid() != 0 {
   581  		return fmt.Errorf("The Docker daemon needs to be run as root")
   582  	}
   583  	return checkKernel()
   584  }
   585  
   586  // configureMaxThreads sets the Go runtime max threads threshold
   587  // which is 90% of the kernel setting from /proc/sys/kernel/threads-max
   588  func configureMaxThreads(config *Config) error {
   589  	mt, err := ioutil.ReadFile("/proc/sys/kernel/threads-max")
   590  	if err != nil {
   591  		return err
   592  	}
   593  	mtint, err := strconv.Atoi(strings.TrimSpace(string(mt)))
   594  	if err != nil {
   595  		return err
   596  	}
   597  	maxThreads := (mtint / 100) * 90
   598  	debug.SetMaxThreads(maxThreads)
   599  	logrus.Debugf("Golang's threads limit set to %d", maxThreads)
   600  	return nil
   601  }
   602  
   603  // configureKernelSecuritySupport configures and validates security support for the kernel
   604  func configureKernelSecuritySupport(config *Config, driverName string) error {
   605  	if config.EnableSelinuxSupport {
   606  		if selinuxEnabled() {
   607  			// As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled
   608  			if driverName == "overlay" {
   609  				return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName)
   610  			}
   611  			logrus.Debug("SELinux enabled successfully")
   612  		} else {
   613  			logrus.Warn("Docker could not enable SELinux on the host system")
   614  		}
   615  	} else {
   616  		selinuxSetDisabled()
   617  	}
   618  	return nil
   619  }
   620  
   621  func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
   622  	netOptions, err := daemon.networkOptions(config, activeSandboxes)
   623  	if err != nil {
   624  		return nil, err
   625  	}
   626  
   627  	controller, err := libnetwork.New(netOptions...)
   628  	if err != nil {
   629  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   630  	}
   631  
   632  	if len(activeSandboxes) > 0 {
   633  		logrus.Infof("There are old running containers, the network config will not take affect")
   634  		return controller, nil
   635  	}
   636  
   637  	// Initialize default network on "null"
   638  	if n, _ := controller.NetworkByName("none"); n == nil {
   639  		if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(true)); err != nil {
   640  			return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
   641  		}
   642  	}
   643  
   644  	// Initialize default network on "host"
   645  	if n, _ := controller.NetworkByName("host"); n == nil {
   646  		if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil {
   647  			return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
   648  		}
   649  	}
   650  	if !config.DisableBridge {
   651  		// Initialize default driver "bridge"
   652  		if err := initBridgeDriver(controller, config); err != nil {
   653  			return nil, err
   654  		}
   655  	}
   656  
   657  	return controller, nil
   658  }
   659  
   660  func driverOptions(config *Config) []nwconfig.Option {
   661  	bridgeConfig := options.Generic{
   662  		"EnableIPForwarding":  config.bridgeConfig.EnableIPForward,
   663  		"EnableIPTables":      config.bridgeConfig.EnableIPTables,
   664  		"EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy}
   665  	bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
   666  
   667  	dOptions := []nwconfig.Option{}
   668  	dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption))
   669  	return dOptions
   670  }
   671  
   672  func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
   673  	if n, err := controller.NetworkByName("bridge"); err == nil {
   674  		if err = n.Delete(); err != nil {
   675  			return fmt.Errorf("could not delete the default bridge network: %v", err)
   676  		}
   677  	}
   678  
   679  	bridgeName := bridge.DefaultBridgeName
   680  	if config.bridgeConfig.Iface != "" {
   681  		bridgeName = config.bridgeConfig.Iface
   682  	}
   683  	netOption := map[string]string{
   684  		bridge.BridgeName:         bridgeName,
   685  		bridge.DefaultBridge:      strconv.FormatBool(true),
   686  		netlabel.DriverMTU:        strconv.Itoa(config.Mtu),
   687  		bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq),
   688  		bridge.EnableICC:          strconv.FormatBool(config.bridgeConfig.InterContainerCommunication),
   689  	}
   690  
   691  	// --ip processing
   692  	if config.bridgeConfig.DefaultIP != nil {
   693  		netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String()
   694  	}
   695  
   696  	var (
   697  		ipamV4Conf *libnetwork.IpamConf
   698  		ipamV6Conf *libnetwork.IpamConf
   699  	)
   700  
   701  	ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   702  
   703  	nw, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
   704  	if err == nil {
   705  		ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
   706  		hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
   707  		if hip.IsGlobalUnicast() {
   708  			ipamV4Conf.Gateway = nw.IP.String()
   709  		}
   710  	}
   711  
   712  	if config.bridgeConfig.IP != "" {
   713  		ipamV4Conf.PreferredPool = config.bridgeConfig.IP
   714  		ip, _, err := net.ParseCIDR(config.bridgeConfig.IP)
   715  		if err != nil {
   716  			return err
   717  		}
   718  		ipamV4Conf.Gateway = ip.String()
   719  	} else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
   720  		logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
   721  	}
   722  
   723  	if config.bridgeConfig.FixedCIDR != "" {
   724  		_, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
   725  		if err != nil {
   726  			return err
   727  		}
   728  
   729  		ipamV4Conf.SubPool = fCIDR.String()
   730  	}
   731  
   732  	if config.bridgeConfig.DefaultGatewayIPv4 != nil {
   733  		ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String()
   734  	}
   735  
   736  	var deferIPv6Alloc bool
   737  	if config.bridgeConfig.FixedCIDRv6 != "" {
   738  		_, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6)
   739  		if err != nil {
   740  			return err
   741  		}
   742  
   743  		// In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has
   744  		// at least 48 host bits, we need to guarantee the current behavior where the containers'
   745  		// IPv6 addresses will be constructed based on the containers' interface MAC address.
   746  		// We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints
   747  		// on this network until after the driver has created the endpoint and returned the
   748  		// constructed address. Libnetwork will then reserve this address with the ipam driver.
   749  		ones, _ := fCIDRv6.Mask.Size()
   750  		deferIPv6Alloc = ones <= 80
   751  
   752  		if ipamV6Conf == nil {
   753  			ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   754  		}
   755  		ipamV6Conf.PreferredPool = fCIDRv6.String()
   756  
   757  		// In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6
   758  		// address belongs to the same network, we need to inform libnetwork about it, so
   759  		// that it can be reserved with IPAM and it will not be given away to somebody else
   760  		for _, nw6 := range nw6List {
   761  			if fCIDRv6.Contains(nw6.IP) {
   762  				ipamV6Conf.Gateway = nw6.IP.String()
   763  				break
   764  			}
   765  		}
   766  	}
   767  
   768  	if config.bridgeConfig.DefaultGatewayIPv6 != nil {
   769  		if ipamV6Conf == nil {
   770  			ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   771  		}
   772  		ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String()
   773  	}
   774  
   775  	v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
   776  	v6Conf := []*libnetwork.IpamConf{}
   777  	if ipamV6Conf != nil {
   778  		v6Conf = append(v6Conf, ipamV6Conf)
   779  	}
   780  	// Initialize default network on "bridge" with the same name
   781  	_, err = controller.NewNetwork("bridge", "bridge", "",
   782  		libnetwork.NetworkOptionEnableIPv6(config.bridgeConfig.EnableIPv6),
   783  		libnetwork.NetworkOptionDriverOpts(netOption),
   784  		libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   785  		libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
   786  	if err != nil {
   787  		return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
   788  	}
   789  	return nil
   790  }
   791  
   792  // setupInitLayer populates a directory with mountpoints suitable
   793  // for bind-mounting things into the container.
   794  //
   795  // This extra layer is used by all containers as the top-most ro layer. It protects
   796  // the container from unwanted side-effects on the rw layer.
   797  func setupInitLayer(initLayer string, rootUID, rootGID int) error {
   798  	for pth, typ := range map[string]string{
   799  		"/dev/pts":         "dir",
   800  		"/dev/shm":         "dir",
   801  		"/proc":            "dir",
   802  		"/sys":             "dir",
   803  		"/.dockerenv":      "file",
   804  		"/etc/resolv.conf": "file",
   805  		"/etc/hosts":       "file",
   806  		"/etc/hostname":    "file",
   807  		"/dev/console":     "file",
   808  		"/etc/mtab":        "/proc/mounts",
   809  	} {
   810  		parts := strings.Split(pth, "/")
   811  		prev := "/"
   812  		for _, p := range parts[1:] {
   813  			prev = filepath.Join(prev, p)
   814  			syscall.Unlink(filepath.Join(initLayer, prev))
   815  		}
   816  
   817  		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
   818  			if os.IsNotExist(err) {
   819  				if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil {
   820  					return err
   821  				}
   822  				switch typ {
   823  				case "dir":
   824  					if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil {
   825  						return err
   826  					}
   827  				case "file":
   828  					f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
   829  					if err != nil {
   830  						return err
   831  					}
   832  					f.Chown(rootUID, rootGID)
   833  					f.Close()
   834  				default:
   835  					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
   836  						return err
   837  					}
   838  				}
   839  			} else {
   840  				return err
   841  			}
   842  		}
   843  	}
   844  
   845  	// Layer is ready to use, if it wasn't before.
   846  	return nil
   847  }
   848  
   849  // Parse the remapped root (user namespace) option, which can be one of:
   850  //   username            - valid username from /etc/passwd
   851  //   username:groupname  - valid username; valid groupname from /etc/group
   852  //   uid                 - 32-bit unsigned int valid Linux UID value
   853  //   uid:gid             - uid value; 32-bit unsigned int Linux GID value
   854  //
   855  //  If no groupname is specified, and a username is specified, an attempt
   856  //  will be made to lookup a gid for that username as a groupname
   857  //
   858  //  If names are used, they are verified to exist in passwd/group
   859  func parseRemappedRoot(usergrp string) (string, string, error) {
   860  
   861  	var (
   862  		userID, groupID     int
   863  		username, groupname string
   864  	)
   865  
   866  	idparts := strings.Split(usergrp, ":")
   867  	if len(idparts) > 2 {
   868  		return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
   869  	}
   870  
   871  	if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
   872  		// must be a uid; take it as valid
   873  		userID = int(uid)
   874  		luser, err := user.LookupUid(userID)
   875  		if err != nil {
   876  			return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
   877  		}
   878  		username = luser.Name
   879  		if len(idparts) == 1 {
   880  			// if the uid was numeric and no gid was specified, take the uid as the gid
   881  			groupID = userID
   882  			lgrp, err := user.LookupGid(groupID)
   883  			if err != nil {
   884  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
   885  			}
   886  			groupname = lgrp.Name
   887  		}
   888  	} else {
   889  		lookupName := idparts[0]
   890  		// special case: if the user specified "default", they want Docker to create or
   891  		// use (after creation) the "dockremap" user/group for root remapping
   892  		if lookupName == defaultIDSpecifier {
   893  			lookupName = defaultRemappedID
   894  		}
   895  		luser, err := user.LookupUser(lookupName)
   896  		if err != nil && idparts[0] != defaultIDSpecifier {
   897  			// error if the name requested isn't the special "dockremap" ID
   898  			return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
   899  		} else if err != nil {
   900  			// special case-- if the username == "default", then we have been asked
   901  			// to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
   902  			// ranges will be used for the user and group mappings in user namespaced containers
   903  			_, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
   904  			if err == nil {
   905  				return defaultRemappedID, defaultRemappedID, nil
   906  			}
   907  			return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
   908  		}
   909  		username = luser.Name
   910  		if len(idparts) == 1 {
   911  			// we only have a string username, and no group specified; look up gid from username as group
   912  			group, err := user.LookupGroup(lookupName)
   913  			if err != nil {
   914  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
   915  			}
   916  			groupID = group.Gid
   917  			groupname = group.Name
   918  		}
   919  	}
   920  
   921  	if len(idparts) == 2 {
   922  		// groupname or gid is separately specified and must be resolved
   923  		// to an unsigned 32-bit gid
   924  		if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
   925  			// must be a gid, take it as valid
   926  			groupID = int(gid)
   927  			lgrp, err := user.LookupGid(groupID)
   928  			if err != nil {
   929  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
   930  			}
   931  			groupname = lgrp.Name
   932  		} else {
   933  			// not a number; attempt a lookup
   934  			if _, err := user.LookupGroup(idparts[1]); err != nil {
   935  				return "", "", fmt.Errorf("Error during groupname lookup for %q: %v", idparts[1], err)
   936  			}
   937  			groupname = idparts[1]
   938  		}
   939  	}
   940  	return username, groupname, nil
   941  }
   942  
   943  func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
   944  	if runtime.GOOS != "linux" && config.RemappedRoot != "" {
   945  		return nil, nil, fmt.Errorf("User namespaces are only supported on Linux")
   946  	}
   947  
   948  	// if the daemon was started with remapped root option, parse
   949  	// the config option to the int uid,gid values
   950  	var (
   951  		uidMaps, gidMaps []idtools.IDMap
   952  	)
   953  	if config.RemappedRoot != "" {
   954  		username, groupname, err := parseRemappedRoot(config.RemappedRoot)
   955  		if err != nil {
   956  			return nil, nil, err
   957  		}
   958  		if username == "root" {
   959  			// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
   960  			// effectively
   961  			logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
   962  			return uidMaps, gidMaps, nil
   963  		}
   964  		logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
   965  		// update remapped root setting now that we have resolved them to actual names
   966  		config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
   967  
   968  		uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
   969  		if err != nil {
   970  			return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
   971  		}
   972  	}
   973  	return uidMaps, gidMaps, nil
   974  }
   975  
   976  func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
   977  	config.Root = rootDir
   978  	// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
   979  	// so that syscalls executing as non-root, operating on subdirectories of the graph root
   980  	// (e.g. mounted layers of a container) can traverse this path.
   981  	// The user namespace support will create subdirectories for the remapped root host uid:gid
   982  	// pair owned by that same uid:gid pair for proper write access to those needed metadata and
   983  	// layer content subtrees.
   984  	if _, err := os.Stat(rootDir); err == nil {
   985  		// root current exists; verify the access bits are correct by setting them
   986  		if err = os.Chmod(rootDir, 0711); err != nil {
   987  			return err
   988  		}
   989  	} else if os.IsNotExist(err) {
   990  		// no root exists yet, create it 0711 with root:root ownership
   991  		if err := os.MkdirAll(rootDir, 0711); err != nil {
   992  			return err
   993  		}
   994  	}
   995  
   996  	// if user namespaces are enabled we will create a subtree underneath the specified root
   997  	// with any/all specified remapped root uid/gid options on the daemon creating
   998  	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
   999  	// `chdir()` to work for containers namespaced to that uid/gid)
  1000  	if config.RemappedRoot != "" {
  1001  		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID))
  1002  		logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
  1003  		// Create the root directory if it doesn't exist
  1004  		if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
  1005  			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
  1006  		}
  1007  	}
  1008  	return nil
  1009  }
  1010  
  1011  // registerLinks writes the links to a file.
  1012  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
  1013  	if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() {
  1014  		return nil
  1015  	}
  1016  
  1017  	for _, l := range hostConfig.Links {
  1018  		name, alias, err := runconfigopts.ParseLink(l)
  1019  		if err != nil {
  1020  			return err
  1021  		}
  1022  		child, err := daemon.GetContainer(name)
  1023  		if err != nil {
  1024  			return fmt.Errorf("Could not get container for %s", name)
  1025  		}
  1026  		for child.HostConfig.NetworkMode.IsContainer() {
  1027  			parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
  1028  			child, err = daemon.GetContainer(parts[1])
  1029  			if err != nil {
  1030  				return fmt.Errorf("Could not get container for %s", parts[1])
  1031  			}
  1032  		}
  1033  		if child.HostConfig.NetworkMode.IsHost() {
  1034  			return runconfig.ErrConflictHostNetworkAndLinks
  1035  		}
  1036  		if err := daemon.registerLink(container, child, alias); err != nil {
  1037  			return err
  1038  		}
  1039  	}
  1040  
  1041  	// After we load all the links into the daemon
  1042  	// set them to nil on the hostconfig
  1043  	return container.WriteHostConfig()
  1044  }
  1045  
  1046  // conditionalMountOnStart is a platform specific helper function during the
  1047  // container start to call mount.
  1048  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
  1049  	return daemon.Mount(container)
  1050  }
  1051  
  1052  // conditionalUnmountOnCleanup is a platform specific helper function called
  1053  // during the cleanup of a container to unmount.
  1054  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
  1055  	return daemon.Unmount(container)
  1056  }
  1057  
  1058  func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
  1059  	if !c.IsRunning() {
  1060  		return nil, errNotRunning{c.ID}
  1061  	}
  1062  	stats, err := daemon.containerd.Stats(c.ID)
  1063  	if err != nil {
  1064  		return nil, err
  1065  	}
  1066  	s := &types.StatsJSON{}
  1067  	cgs := stats.CgroupStats
  1068  	if cgs != nil {
  1069  		s.BlkioStats = types.BlkioStats{
  1070  			IoServiceBytesRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceBytesRecursive),
  1071  			IoServicedRecursive:     copyBlkioEntry(cgs.BlkioStats.IoServicedRecursive),
  1072  			IoQueuedRecursive:       copyBlkioEntry(cgs.BlkioStats.IoQueuedRecursive),
  1073  			IoServiceTimeRecursive:  copyBlkioEntry(cgs.BlkioStats.IoServiceTimeRecursive),
  1074  			IoWaitTimeRecursive:     copyBlkioEntry(cgs.BlkioStats.IoWaitTimeRecursive),
  1075  			IoMergedRecursive:       copyBlkioEntry(cgs.BlkioStats.IoMergedRecursive),
  1076  			IoTimeRecursive:         copyBlkioEntry(cgs.BlkioStats.IoTimeRecursive),
  1077  			SectorsRecursive:        copyBlkioEntry(cgs.BlkioStats.SectorsRecursive),
  1078  		}
  1079  		cpu := cgs.CpuStats
  1080  		s.CPUStats = types.CPUStats{
  1081  			CPUUsage: types.CPUUsage{
  1082  				TotalUsage:        cpu.CpuUsage.TotalUsage,
  1083  				PercpuUsage:       cpu.CpuUsage.PercpuUsage,
  1084  				UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
  1085  				UsageInUsermode:   cpu.CpuUsage.UsageInUsermode,
  1086  			},
  1087  			ThrottlingData: types.ThrottlingData{
  1088  				Periods:          cpu.ThrottlingData.Periods,
  1089  				ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
  1090  				ThrottledTime:    cpu.ThrottlingData.ThrottledTime,
  1091  			},
  1092  		}
  1093  		mem := cgs.MemoryStats.Usage
  1094  		s.MemoryStats = types.MemoryStats{
  1095  			Usage:    mem.Usage,
  1096  			MaxUsage: mem.MaxUsage,
  1097  			Stats:    cgs.MemoryStats.Stats,
  1098  			Failcnt:  mem.Failcnt,
  1099  			Limit:    mem.Limit,
  1100  		}
  1101  		// if the container does not set memory limit, use the machineMemory
  1102  		if mem.Limit > daemon.statsCollector.machineMemory && daemon.statsCollector.machineMemory > 0 {
  1103  			s.MemoryStats.Limit = daemon.statsCollector.machineMemory
  1104  		}
  1105  		if cgs.PidsStats != nil {
  1106  			s.PidsStats = types.PidsStats{
  1107  				Current: cgs.PidsStats.Current,
  1108  			}
  1109  		}
  1110  	}
  1111  	s.Read, err = ptypes.Timestamp(stats.Timestamp)
  1112  	if err != nil {
  1113  		return nil, err
  1114  	}
  1115  	return s, nil
  1116  }
  1117  
  1118  // setDefaultIsolation determines the default isolation mode for the
  1119  // daemon to run in. This is only applicable on Windows
  1120  func (daemon *Daemon) setDefaultIsolation() error {
  1121  	return nil
  1122  }
  1123  
  1124  func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
  1125  	var layers []string
  1126  	for _, l := range rootfs.DiffIDs {
  1127  		layers = append(layers, l.String())
  1128  	}
  1129  	return types.RootFS{
  1130  		Type:   rootfs.Type,
  1131  		Layers: layers,
  1132  	}
  1133  }
  1134  
  1135  // setupDaemonProcess sets various settings for the daemon's process
  1136  func setupDaemonProcess(config *Config) error {
  1137  	// setup the daemons oom_score_adj
  1138  	return setupOOMScoreAdj(config.OOMScoreAdjust)
  1139  }
  1140  
  1141  func setupOOMScoreAdj(score int) error {
  1142  	f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0)
  1143  	if err != nil {
  1144  		return err
  1145  	}
  1146  	_, err = f.WriteString(strconv.Itoa(score))
  1147  	f.Close()
  1148  	return err
  1149  }