switchroot.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package switchroot
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path"
  7. "strings"
  8. "syscall"
  9. "github.com/rancher/os/config"
  10. "github.com/rancher/os/pkg/dfs"
  11. "github.com/rancher/os/pkg/init/fsmount"
  12. "github.com/rancher/os/pkg/log"
  13. "github.com/docker/docker/pkg/archive"
  14. )
  15. func SwitchRoot(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  16. if !fsmount.ShouldSwitchRoot {
  17. return cfg, nil
  18. }
  19. log.Debugf("Switching to new root at %s %s", config.StateDir, cfg.Rancher.State.Directory)
  20. if err := switchRoot(config.StateDir, cfg.Rancher.State.Directory, cfg.Rancher.RmUsr); err != nil {
  21. return cfg, err
  22. }
  23. return cfg, nil
  24. }
  25. func cleanupTarget(rootfs, targetUsr, usr, usrVer, tmpDir string) (bool, error) {
  26. log.Debugf("Deleting %s", targetUsr)
  27. if err := os.Remove(targetUsr); err != nil && !os.IsNotExist(err) {
  28. log.Errorf("Failed to delete %s, possibly invalid RancherOS state partition: %v", targetUsr, err)
  29. return false, err
  30. }
  31. if err := dfs.CreateSymlink(usrVer, path.Join(rootfs, "usr")); err != nil {
  32. return false, err
  33. }
  34. log.Debugf("Deleting %s", tmpDir)
  35. if err := os.RemoveAll(tmpDir); err != nil {
  36. // Don't care if this fails
  37. log.Errorf("Failed to cleanup temp directory %s: %v", tmpDir, err)
  38. }
  39. if _, err := os.Stat(usr); err == nil {
  40. return false, nil
  41. }
  42. return true, nil
  43. }
  44. func copyMoveRoot(rootfs string, rmUsr bool) error {
  45. usrVer := fmt.Sprintf("usr-%s", config.Version)
  46. usr := path.Join(rootfs, usrVer)
  47. targetUsr := path.Join(rootfs, "usr")
  48. tmpDir := path.Join(rootfs, "tmp")
  49. if rmUsr {
  50. log.Warnf("Development setup. Removing old usr: %s", usr)
  51. if err := os.RemoveAll(usr); err != nil {
  52. // Don't care if this fails
  53. log.Errorf("Failed to remove %s: %v", usr, err)
  54. }
  55. }
  56. if cont, err := cleanupTarget(rootfs, targetUsr, usr, usrVer, tmpDir); !cont {
  57. return err
  58. }
  59. log.Debugf("Creating temp dir directory %s", tmpDir)
  60. if err := os.MkdirAll(tmpDir, 0755); err != nil {
  61. return err
  62. }
  63. usrVerTmp, err := ioutil.TempDir(tmpDir, usrVer)
  64. if err != nil {
  65. return err
  66. }
  67. log.Debugf("Copying to temp dir %s", usrVerTmp)
  68. if err := archive.CopyWithTar("/usr", usrVerTmp); err != nil {
  69. return err
  70. }
  71. log.Debugf("Renaming %s => %s", usrVerTmp, usr)
  72. if err := os.Rename(usrVerTmp, usr); err != nil {
  73. return err
  74. }
  75. files, err := ioutil.ReadDir("/")
  76. if err != nil {
  77. return err
  78. }
  79. for _, file := range files {
  80. filename := path.Join("/", file.Name())
  81. if filename == rootfs || strings.HasPrefix(rootfs, filename+"/") {
  82. log.Debugf("Skipping Deleting %s", filename)
  83. continue
  84. }
  85. log.Debugf("Deleting %s", filename)
  86. if err := os.RemoveAll(filename); err != nil {
  87. return err
  88. }
  89. }
  90. return nil
  91. }
  92. func switchRoot(rootfs, subdir string, rmUsr bool) error {
  93. if err := syscall.Unmount(config.OemDir, 0); err != nil {
  94. log.Debugf("Not umounting OEM: %v", err)
  95. }
  96. if subdir != "" {
  97. fullRootfs := path.Join(rootfs, subdir)
  98. if _, err := os.Stat(fullRootfs); os.IsNotExist(err) {
  99. if err := os.MkdirAll(fullRootfs, 0755); err != nil {
  100. log.Errorf("Failed to create directory %s: %v", fullRootfs, err)
  101. return err
  102. }
  103. }
  104. log.Debugf("Bind mounting mount %s to %s", fullRootfs, rootfs)
  105. if err := syscall.Mount(fullRootfs, rootfs, "", syscall.MS_BIND, ""); err != nil {
  106. log.Errorf("Failed to bind mount subdir for %s: %v", fullRootfs, err)
  107. return err
  108. }
  109. }
  110. for _, i := range []string{"/dev", "/sys", "/proc", "/run"} {
  111. log.Debugf("Moving mount %s to %s", i, path.Join(rootfs, i))
  112. if err := os.MkdirAll(path.Join(rootfs, i), 0755); err != nil {
  113. return err
  114. }
  115. if err := syscall.Mount(i, path.Join(rootfs, i), "", syscall.MS_MOVE, ""); err != nil {
  116. return err
  117. }
  118. }
  119. if err := copyMoveRoot(rootfs, rmUsr); err != nil {
  120. return err
  121. }
  122. log.Debugf("chdir %s", rootfs)
  123. if err := syscall.Chdir(rootfs); err != nil {
  124. return err
  125. }
  126. log.Debugf("mount MS_MOVE %s", rootfs)
  127. if err := syscall.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil {
  128. return err
  129. }
  130. log.Debug("chroot .")
  131. if err := syscall.Chroot("."); err != nil {
  132. return err
  133. }
  134. log.Debug("chdir /")
  135. if err := syscall.Chdir("/"); err != nil {
  136. return err
  137. }
  138. log.Debugf("Successfully moved to new root at %s", path.Join(rootfs, subdir))
  139. os.Unsetenv("DOCKER_RAMDISK")
  140. return nil
  141. }