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