init.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // +build linux
  2. package mount
  3. import (
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "syscall"
  8. "github.com/dotcloud/docker/pkg/label"
  9. "github.com/dotcloud/docker/pkg/libcontainer"
  10. "github.com/dotcloud/docker/pkg/libcontainer/mount/nodes"
  11. "github.com/dotcloud/docker/pkg/system"
  12. )
  13. // default mount point flags
  14. const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
  15. type mount struct {
  16. source string
  17. path string
  18. device string
  19. flags int
  20. data string
  21. }
  22. // InitializeMountNamespace setups up the devices, mount points, and filesystems for use inside a
  23. // new mount namepsace
  24. func InitializeMountNamespace(rootfs, console string, container *libcontainer.Container) error {
  25. var (
  26. err error
  27. flag = syscall.MS_PRIVATE
  28. )
  29. if container.NoPivotRoot {
  30. flag = syscall.MS_SLAVE
  31. }
  32. if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil {
  33. return fmt.Errorf("mounting / as slave %s", err)
  34. }
  35. if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
  36. return fmt.Errorf("mouting %s as bind %s", rootfs, err)
  37. }
  38. if err := mountSystem(rootfs, container); err != nil {
  39. return fmt.Errorf("mount system %s", err)
  40. }
  41. if err := setupBindmounts(rootfs, container.Mounts); err != nil {
  42. return fmt.Errorf("bind mounts %s", err)
  43. }
  44. if err := nodes.CopyN(rootfs, nodes.DefaultNodes); err != nil {
  45. return fmt.Errorf("copy dev nodes %s", err)
  46. }
  47. if err := SetupPtmx(rootfs, console, container.Context["mount_label"]); err != nil {
  48. return err
  49. }
  50. if err := system.Chdir(rootfs); err != nil {
  51. return fmt.Errorf("chdir into %s %s", rootfs, err)
  52. }
  53. if container.NoPivotRoot {
  54. err = MsMoveRoot(rootfs)
  55. } else {
  56. err = PivotRoot(rootfs)
  57. }
  58. if err != nil {
  59. return err
  60. }
  61. if container.ReadonlyFs {
  62. if err := SetReadonly(); err != nil {
  63. return fmt.Errorf("set readonly %s", err)
  64. }
  65. }
  66. system.Umask(0022)
  67. return nil
  68. }
  69. // mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
  70. // inside the mount namespace
  71. func mountSystem(rootfs string, container *libcontainer.Container) error {
  72. for _, m := range newSystemMounts(rootfs, container.Context["mount_label"], container.Mounts) {
  73. if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
  74. return fmt.Errorf("mkdirall %s %s", m.path, err)
  75. }
  76. if err := system.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil {
  77. return fmt.Errorf("mounting %s into %s %s", m.source, m.path, err)
  78. }
  79. }
  80. return nil
  81. }
  82. func createIfNotExists(path string, isDir bool) error {
  83. if _, err := os.Stat(path); err != nil {
  84. if os.IsNotExist(err) {
  85. if isDir {
  86. if err := os.MkdirAll(path, 0755); err != nil {
  87. return err
  88. }
  89. } else {
  90. if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
  91. return err
  92. }
  93. f, err := os.OpenFile(path, os.O_CREATE, 0755)
  94. if err != nil {
  95. return err
  96. }
  97. f.Close()
  98. }
  99. }
  100. }
  101. return nil
  102. }
  103. func setupBindmounts(rootfs string, bindMounts libcontainer.Mounts) error {
  104. for _, m := range bindMounts.OfType("bind") {
  105. var (
  106. flags = syscall.MS_BIND | syscall.MS_REC
  107. dest = filepath.Join(rootfs, m.Destination)
  108. )
  109. if !m.Writable {
  110. flags = flags | syscall.MS_RDONLY
  111. }
  112. stat, err := os.Stat(m.Source)
  113. if err != nil {
  114. return err
  115. }
  116. if err := createIfNotExists(dest, stat.IsDir()); err != nil {
  117. return fmt.Errorf("Creating new bind-mount target, %s", err)
  118. }
  119. if err := system.Mount(m.Source, dest, "bind", uintptr(flags), ""); err != nil {
  120. return fmt.Errorf("mounting %s into %s %s", m.Source, dest, err)
  121. }
  122. if !m.Writable {
  123. if err := system.Mount(m.Source, dest, "bind", uintptr(flags|syscall.MS_REMOUNT), ""); err != nil {
  124. return fmt.Errorf("remounting %s into %s %s", m.Source, dest, err)
  125. }
  126. }
  127. if m.Private {
  128. if err := system.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil {
  129. return fmt.Errorf("mounting %s private %s", dest, err)
  130. }
  131. }
  132. }
  133. return nil
  134. }
  135. // TODO: this is crappy right now and should be cleaned up with a better way of handling system and
  136. // standard bind mounts allowing them to be more dynamic
  137. func newSystemMounts(rootfs, mountLabel string, mounts libcontainer.Mounts) []mount {
  138. systemMounts := []mount{
  139. {source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
  140. {source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags},
  141. {source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1777,size=65536k", mountLabel)},
  142. {source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: label.FormatMountLabel("newinstance,ptmxmode=0666,mode=620,gid=5", mountLabel)},
  143. }
  144. if len(mounts.OfType("devtmpfs")) == 1 {
  145. systemMounts = append([]mount{{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: label.FormatMountLabel("mode=755", mountLabel)}}, systemMounts...)
  146. }
  147. return systemMounts
  148. }