func (daemon *Daemon) mountVolumes(container *Container) error { mounts, err := daemon.setupMounts(container) if err != nil { return err } for _, m := range mounts { dest, err := container.GetResourcePath(m.Destination) if err != nil { return err } var stat os.FileInfo stat, err = os.Stat(m.Source) if err != nil { return err } if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { return err } opts := "rbind,ro" if m.Writable { opts = "rbind,rw" } if err := mount.Mount(m.Source, dest, "bind", opts); err != nil { return err } } return nil }
func (container *Container) mountVolumes() error { for dest, source := range container.Volumes { v := container.daemon.volumes.Get(source) if v == nil { return fmt.Errorf("could not find volume for %s:%s, impossible to mount", source, dest) } destPath, err := container.GetResourcePath(dest) if err != nil { return err } if err := mount.Mount(source, destPath, "bind", "rbind,rw"); err != nil { return fmt.Errorf("error while mounting volume %s: %v", source, err) } } for _, mnt := range container.specialMounts() { destPath, err := container.GetResourcePath(mnt.Destination) if err != nil { return err } if err := mount.Mount(mnt.Source, destPath, "bind", "bind,rw"); err != nil { return fmt.Errorf("error while mounting volume %s: %v", mnt.Source, err) } } return nil }
func bindMount(bindDir string, rootDir string, readonly bool) error { var srcDir, destDir string d := strings.SplitN(bindDir, ":", 2) if len(d) < 2 { srcDir = d[0] } else { srcDir, destDir = d[0], d[1] } if destDir == "" { destDir = srcDir } ok, err := osutil.IsDirEmpty(srcDir) if err != nil { return err } if ok { if _, err := os.Create(fp.Join(srcDir, ".droot.keep")); err != nil { return errwrap.Wrapf(err, "Failed to create .droot.keep: {{err}}") } } containerDir := fp.Join(rootDir, destDir) if err := fileutils.CreateIfNotExists(containerDir, true); err != nil { // mkdir -p return errwrap.Wrapff(err, "Failed to create directory: %s: {{err}}", containerDir) } ok, err = osutil.IsDirEmpty(containerDir) if err != nil { return err } if ok { log.Debug("bind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "bind,rw"); err != nil { return errwrap.Wrapff(err, "Failed to bind mount %s: {{err}}", containerDir) } if readonly { log.Debug("robind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "remount,ro,bind"); err != nil { return errwrap.Wrapff(err, "Failed to robind mount %s: {{err}}", containerDir) } } } return nil }
func (d *driver) Mount( device, target, mountOptions, mountLabel string) error { if d.isNfsDevice(device) { if err := d.nfsMount(device, target); err != nil { return err } os.MkdirAll(d.volumeMountPath(target), d.fileModeMountPath()) os.Chmod(d.volumeMountPath(target), d.fileModeMountPath()) return nil } fsType, err := probeFsType(device) if err != nil { return err } options := label.FormatMountLabel("", mountLabel) options = fmt.Sprintf("%s,%s", mountOptions, mountLabel) if fsType == "xfs" { options = fmt.Sprintf("%s,nouuid", mountOptions) } if err := mount.Mount(device, target, fsType, options); err != nil { return fmt.Errorf("Couldn't mount directory %s at %s: %s", device, target, err) } os.MkdirAll(d.volumeMountPath(target), d.fileModeMountPath()) os.Chmod(d.volumeMountPath(target), d.fileModeMountPath()) return nil }
func (container *Container) Copy(resource string) (io.ReadCloser, error) { container.Lock() defer container.Unlock() var err error if err := container.Mount(); err != nil { return nil, err } defer func() { if err != nil { // unmount any volumes container.UnmountVolumes(true) // unmount the container's rootfs container.Unmount() } }() mounts, err := container.setupMounts() if err != nil { return nil, err } for _, m := range mounts { dest, err := container.GetResourcePath(m.Destination) if err != nil { return nil, err } if err := mount.Mount(m.Source, dest, "bind", "rbind,ro"); err != nil { return nil, err } } basePath, err := container.GetResourcePath(resource) if err != nil { return nil, err } stat, err := os.Stat(basePath) if err != nil { return nil, err } var filter []string if !stat.IsDir() { d, f := filepath.Split(basePath) basePath = d filter = []string{f} } else { filter = []string{filepath.Base(basePath)} basePath = filepath.Dir(basePath) } archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ Compression: archive.Uncompressed, IncludeFiles: filter, }) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.UnmountVolumes(true) container.Unmount() return err }), nil }
func (v *localVolume) mount() error { if v.opts.MountDevice == "" { return fmt.Errorf("missing device in volume options") } err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, v.opts.MountOpts) return errors.Wrapf(err, "error while mounting volume with options: %s", v.opts) }
// Test recursive bind mount works by default func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) { // /tmp gets permission denied testRequires(c, NotUserNamespace) tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test") if err != nil { c.Fatal(err) } defer os.RemoveAll(tmpDir) // Create a temporary tmpfs mount. tmpfsDir := filepath.Join(tmpDir, "tmpfs") if err := os.MkdirAll(tmpfsDir, 0777); err != nil { c.Fatalf("failed to mkdir at %s - %s", tmpfsDir, err) } if err := mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""); err != nil { c.Fatalf("failed to create a tmpfs mount at %s - %s", tmpfsDir, err) } f, err := ioutil.TempFile(tmpfsDir, "touch-me") if err != nil { c.Fatal(err) } defer f.Close() runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs") out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd) if err != nil && exitCode != 0 { c.Fatal(out, stderr, err) } if !strings.Contains(out, filepath.Base(f.Name())) { c.Fatal("Recursive bind mount test failed. Expected file not found") } }
// Get returns the mountpoint for the given id after creating the target directories if necessary. func (d *Driver) Get(id, mountLabel string) (string, error) { mountpoint := d.mountPath(id) filesystem := d.zfsPath(id) options := label.FormatMountLabel("", mountLabel) logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil { return "", err } if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil { return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) } // this could be our first mount after creation of the filesystem, and the root dir may still have root // permissions instead of the remapped root uid:gid (if user namespaces are enabled): if err := os.Chown(mountpoint, rootUID, rootGID); err != nil { return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err) } return mountpoint, nil }
func mountToRootfs(m *specs.Mount, rootfs, mountLabel string) error { // TODO: we don't use mountLabel here because it looks like mountLabel is // only significant when SELinux is enabled. var ( dest = m.Destination ) if !strings.HasPrefix(dest, rootfs) { dest = filepath.Join(rootfs, dest) } switch m.Type { case "proc", "sysfs", "mqueue", "tmpfs", "cgroup", "devpts": glog.V(3).Infof("Skip mount point %q of type %s", m.Destination, m.Type) return nil case "bind": stat, err := os.Stat(m.Source) if err != nil { // error out if the source of a bind mount does not exist as we will be // unable to bind anything to it. return err } // ensure that the destination of the bind mount is resolved of symlinks at mount time because // any previous mounts can invalidate the next mount's destination. // this can happen when a user specifies mounts within other mounts to cause breakouts or other // evil stuff to try to escape the container's rootfs. if dest, err = symlink.FollowSymlinkInScope(filepath.Join(rootfs, m.Destination), rootfs); err != nil { return err } if err := checkMountDestination(rootfs, dest); err != nil { return err } // update the mount with the correct dest after symlinks are resolved. m.Destination = dest if err := createIfNotExists(dest, stat.IsDir()); err != nil { return err } if err := mount.Mount(m.Source, dest, m.Type, strings.Join(m.Options, ",")); err != nil { return err } default: if err := os.MkdirAll(dest, 0755); err != nil { return err } return mount.Mount(m.Source, dest, m.Type, strings.Join(m.Options, ",")) } return nil }
func bindMount(bindDir string, rootDir string, readonly bool) error { var srcDir, destDir string d := strings.SplitN(bindDir, ":", 2) if len(d) < 2 { srcDir = d[0] } else { srcDir, destDir = d[0], d[1] } if destDir == "" { destDir = srcDir } ok, err := IsDirEmpty(srcDir) if err != nil { return err } containerDir := fp.Join(rootDir, destDir) if err := fileutils.CreateIfNotExists(containerDir, true); err != nil { // mkdir -p log.FATAL.Fatalln("Failed to create directory:", containerDir, err) } ok, err = IsDirEmpty(containerDir) if err != nil { return err } if ok { log.DEBUG.Println("bind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "bind,rw"); err != nil { log.FATAL.Fatalln("Failed to bind mount:", containerDir, err) } if readonly { log.DEBUG.Println("robind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "remount,ro,bind"); err != nil { log.FATAL.Fatalln("Failed to robind mount:", containerDir, err) } } } return nil }
func MakePrivate(mountPoint string) error { mounted, err := mount.Mounted(mountPoint) if err != nil { return err } if !mounted { if err := mount.Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { return err } } return mount.ForceMount("", mountPoint, "none", "private") }
func Mount(device, directory, fsType, options string) error { if err := mountProc(); err != nil { return nil } if _, err := os.Stat(directory); os.IsNotExist(err) { err = os.MkdirAll(directory, 0755) if err != nil { return err } } return mount.Mount(device, directory, fsType, options) }
func MountIfNotMounted(device, target, mType, options string) error { mounted, err := mount.Mounted(target) if err != nil { return err } if !mounted { log.Debug("mount", device, target, mType, options) if err := mount.Mount(device, target, mType, options); err != nil { return err } } return nil }
func (d *Driver) Get(id, mountLabel string) (string, error) { mountpoint := d.MountPath(id) filesystem := d.ZfsPath(id) log.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, mountLabel) // Create the target directories if they don't exist if err := os.MkdirAll(mountpoint, 0755); err != nil && !os.IsExist(err) { return "", err } err := mount.Mount(filesystem, mountpoint, "zfs", mountLabel) if err != nil { return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) } return mountpoint, nil }
func (daemon *Daemon) mountVolumes(container *container.Container) error { mounts, err := daemon.setupMounts(container) if err != nil { return err } for _, m := range mounts { dest, err := container.GetResourcePath(m.Destination) if err != nil { return err } var stat os.FileInfo stat, err = os.Stat(m.Source) if err != nil { return err } if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { return err } opts := "rbind,ro" if m.Writable { opts = "rbind,rw" } if err := mount.Mount(m.Source, dest, bindMountType, opts); err != nil { return err } // mountVolumes() seems to be called for temporary mounts // outside the container. Soon these will be unmounted with // lazy unmount option and given we have mounted the rbind, // all the submounts will propagate if these are shared. If // daemon is running in host namespace and has / as shared // then these unmounts will propagate and unmount original // mount as well. So make all these mounts rprivate. // Do not use propagation property of volume as that should // apply only when mounting happen inside the container. if err := mount.MakeRPrivate(dest); err != nil { return err } } return nil }
func (v *localVolume) mount() error { if v.opts.MountDevice == "" { return fmt.Errorf("missing device in volume options") } mountOpts := v.opts.MountOpts if v.opts.MountType == "nfs" { if addrValue := getAddress(v.opts.MountOpts); addrValue != "" && net.ParseIP(addrValue).To4() == nil { ipAddr, err := net.ResolveIPAddr("ip", addrValue) if err != nil { return errors.Wrapf(err, "error resolving passed in nfs address") } mountOpts = strings.Replace(mountOpts, "addr="+addrValue, "addr="+ipAddr.String(), 1) } } err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, mountOpts) return errors.Wrapf(err, "error while mounting volume with options: %s", v.opts) }
func (driver *Driver) Mount(device, target, mountOptions, mountLabel string) error { fsType, err := probeFsType(device) if err != nil { return err } options := label.FormatMountLabel("", mountLabel) options = fmt.Sprintf("%s,%s", mountOptions, mountLabel) if fsType == "xfs" { options = fmt.Sprintf("%s,nouuid", mountOptions) } if err := mount.Mount(device, target, fsType, options); err != nil { return fmt.Errorf("Couldn't mount directory %s at %s: %s", device, target, err) } return nil }
func setupSharedRoot(c *config.CloudConfig) (*config.CloudConfig, error) { if c.Rancher.NoSharedRoot { return c, nil } if isInitrd() { for _, i := range []string{"/mnt", "/media"} { if err := os.Mkdir(i, 0755); err != nil { return c, err } if err := mount.Mount("tmpfs", i, "tmpfs", "rw"); err != nil { return c, err } if err := mount.MakeShared(i); err != nil { return c, err } } return c, nil } return c, mount.MakeShared("/") }
// Test recursive bind mount works by default func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) { // /tmp gets permission denied testRequires(c, NotUserNamespace, SameHostDaemon) tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test") c.Assert(err, checker.IsNil) defer os.RemoveAll(tmpDir) // Create a temporary tmpfs mount. tmpfsDir := filepath.Join(tmpDir, "tmpfs") c.Assert(os.MkdirAll(tmpfsDir, 0777), checker.IsNil, check.Commentf("failed to mkdir at %s", tmpfsDir)) c.Assert(mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""), checker.IsNil, check.Commentf("failed to create a tmpfs mount at %s", tmpfsDir)) f, err := ioutil.TempFile(tmpfsDir, "touch-me") c.Assert(err, checker.IsNil) defer f.Close() runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs") out, _, _, err := runCommandWithStdoutStderr(runCmd) c.Assert(err, checker.IsNil) c.Assert(out, checker.Contains, filepath.Base(f.Name()), check.Commentf("Recursive bind mount test failed. Expected file not found")) }
// Get returns the mountpoint for the given id after creating the target directories if necessary. func (d *Driver) Get(id, mountLabel string) (string, error) { mountpoint := d.mountPath(id) filesystem := d.zfsPath(id) options := label.FormatMountLabel("", mountLabel) logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil { return "", err } err = mount.Mount(filesystem, mountpoint, "zfs", options) if err != nil { return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) } return mountpoint, nil }
// Test recursive bind mount works by default func TestDockerRunWithVolumesIsRecursive(t *testing.T) { tmpDir, err := ioutil.TempDir("", "docker_recursive_mount_test") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpDir) // Create a temporary tmpfs mount. tmpfsDir := filepath.Join(tmpDir, "tmpfs") if err := os.MkdirAll(tmpfsDir, 0777); err != nil { t.Fatalf("failed to mkdir at %s - %s", tmpfsDir, err) } if err := mount.Mount("tmpfs", tmpfsDir, "tmpfs", ""); err != nil { t.Fatalf("failed to create a tmpfs mount at %s - %s", tmpfsDir, err) } f, err := ioutil.TempFile(tmpfsDir, "touch-me") if err != nil { t.Fatal(err) } defer f.Close() runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", fmt.Sprintf("%s:/tmp:ro", tmpDir), "busybox:latest", "ls", "/tmp/tmpfs") out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd) if err != nil && exitCode != 0 { t.Fatal(out, stderr, err) } if !strings.Contains(out, filepath.Base(f.Name())) { t.Fatal("Recursive bind mount test failed. Expected file not found") } deleteAllContainers() logDone("run - volumes are bind mounted recuursively") }
// chroot on linux uses pivot_root instead of chroot // pivot_root takes a new root and an old root. // Old root must be a sub-dir of new root, it is where the current rootfs will reside after the call to pivot_root. // New root is where the new rootfs is set to. // Old root is removed after the call to pivot_root so it is no longer available under the new root. // This is similar to how libcontainer sets up a container's rootfs func chroot(path string) (err error) { // if the engine is running in a user namespace we need to use actual chroot if rsystem.RunningInUserNS() { return realChroot(path) } if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil { return fmt.Errorf("Error creating mount namespace before pivot: %v", err) } // make everything in new ns private if err := mount.MakeRPrivate("/"); err != nil { return err } if mounted, _ := mount.Mounted(path); !mounted { if err := mount.Mount(path, path, "bind", "rbind,rw"); err != nil { return realChroot(path) } } // setup oldRoot for pivot_root pivotDir, err := ioutil.TempDir(path, ".pivot_root") if err != nil { return fmt.Errorf("Error setting up pivot dir: %v", err) } var mounted bool defer func() { if mounted { // make sure pivotDir is not mounted before we try to remove it if errCleanup := syscall.Unmount(pivotDir, syscall.MNT_DETACH); errCleanup != nil { if err == nil { err = errCleanup } return } } errCleanup := os.Remove(pivotDir) // pivotDir doesn't exist if pivot_root failed and chroot+chdir was successful // because we already cleaned it up on failed pivot_root if errCleanup != nil && !os.IsNotExist(errCleanup) { errCleanup = fmt.Errorf("Error cleaning up after pivot: %v", errCleanup) if err == nil { err = errCleanup } } }() if err := syscall.PivotRoot(path, pivotDir); err != nil { // If pivot fails, fall back to the normal chroot after cleaning up temp dir if err := os.Remove(pivotDir); err != nil { return fmt.Errorf("Error cleaning up after failed pivot: %v", err) } return realChroot(path) } mounted = true // This is the new path for where the old root (prior to the pivot) has been moved to // This dir contains the rootfs of the caller, which we need to remove so it is not visible during extraction pivotDir = filepath.Join("/", filepath.Base(pivotDir)) if err := syscall.Chdir("/"); err != nil { return fmt.Errorf("Error changing to new root: %v", err) } // Make the pivotDir (where the old root lives) private so it can be unmounted without propagating to the host if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil { return fmt.Errorf("Error making old root private after pivot: %v", err) } // Now unmount the old root so it's no longer visible from the new root if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { return fmt.Errorf("Error while unmounting old root after pivot: %v", err) } mounted = false return nil }
// Mount mounts an ext4 formatted device at the given path. From the Docker // mount pkg, args must in the form arg=val. func (e *Ext4) Mount(devPath, targetPath string, options []string) error { defer trace.End(trace.Begin(devPath)) log.Infof("Mounting %s to %s", devPath, targetPath) return mount.Mount(devPath, targetPath, "ext4", strings.Join(options, ",")) }
func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { if len(c.SecretReferences) == 0 { return nil } localMountPath := c.SecretMountPath() logrus.Debugf("secrets: setting up secret dir: %s", localMountPath) defer func() { if setupErr != nil { // cleanup _ = detachMounted(localMountPath) if err := os.RemoveAll(localMountPath); err != nil { log.Errorf("error cleaning up secret mount: %s", err) } } }() // retrieve possible remapped range start for root UID, GID rootUID, rootGID := daemon.GetRemappedUIDGID() // create tmpfs if err := idtools.MkdirAllAs(localMountPath, 0700, rootUID, rootGID); err != nil { return errors.Wrap(err, "error creating secret local mount path") } tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootUID, rootGID) if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil { return errors.Wrap(err, "unable to setup secret mount") } for _, s := range c.SecretReferences { if c.SecretStore == nil { return fmt.Errorf("secret store is not initialized") } // TODO (ehazlett): use type switch when more are supported if s.File == nil { return fmt.Errorf("secret target type is not a file target") } targetPath := filepath.Clean(s.File.Name) // ensure that the target is a filename only; no paths allowed if targetPath != filepath.Base(targetPath) { return fmt.Errorf("error creating secret: secret must not be a path") } fPath := filepath.Join(localMountPath, targetPath) if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil { return errors.Wrap(err, "error creating secret mount path") } logrus.WithFields(logrus.Fields{ "name": s.File.Name, "path": fPath, }).Debug("injecting secret") secret := c.SecretStore.Get(s.SecretID) if secret == nil { return fmt.Errorf("unable to get secret from secret store") } if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil { return errors.Wrap(err, "error injecting secret") } uid, err := strconv.Atoi(s.File.UID) if err != nil { return err } gid, err := strconv.Atoi(s.File.GID) if err != nil { return err } if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil { return errors.Wrap(err, "error setting ownership for secret") } } // remount secrets ro if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil { return errors.Wrap(err, "unable to remount secret dir as readonly") } return nil }
func (v *localVolume) mount() error { if v.opts.MountDevice == "" { return fmt.Errorf("missing device in volume options") } return mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, v.opts.MountOpts) }
func doRun(c *cli.Context) error { command := c.Args() if len(command) < 1 { cli.ShowCommandHelp(c, "run") return errors.New("command required") } rootDir := c.String("root") if rootDir == "" { cli.ShowCommandHelp(c, "run") return errors.New("--root option required") } if !osutil.ExistsDir(rootDir) { return fmt.Errorf("No such directory %s:", rootDir) } var err error uid, gid := os.Getuid(), os.Getgid() if group := c.String("group"); group != "" { if gid, err = osutil.LookupGroup(group); err != nil { return fmt.Errorf("Failed to lookup group:", err) } } if user := c.String("user"); user != "" { if uid, err = osutil.LookupUser(user); err != nil { return fmt.Errorf("Failed to lookup user:"******"copy-files") { for _, f := range copyFiles { srcFile, destFile := fp.Join("/", f), fp.Join(rootDir, f) if err := osutil.Cp(srcFile, destFile); err != nil { return fmt.Errorf("Failed to copy %s:", f, err) } if err := os.Lchown(destFile, uid, gid); err != nil { return fmt.Errorf("Failed to lchown %s:", f, err) } } } // mount -t proc none {{rootDir}}/proc if err := mount.Mount("none", fp.Join(rootDir, "/proc"), "proc", ""); err != nil { return fmt.Errorf("Failed to mount /proc: %s", err) } // mount --rbind /sys {{rootDir}}/sys if err := mount.Mount("/sys", fp.Join(rootDir, "/sys"), "none", "rbind"); err != nil { return fmt.Errorf("Failed to mount /sys: %s", err) } for _, dir := range c.StringSlice("bind") { if err := bindMount(dir, rootDir, false); err != nil { return fmt.Errorf("Failed to bind mount %s:", dir, err) } } for _, dir := range c.StringSlice("robind") { if err := bindMount(dir, rootDir, true); err != nil { return fmt.Errorf("Failed to robind mount %s:", dir, err) } } // create symlinks if err := osutil.Symlink("../run/lock", fp.Join(rootDir, "/var/lock")); err != nil { return fmt.Errorf("Failed to symlink lock file:", err) } if err := createDevices(rootDir, uid, gid); err != nil { return fmt.Errorf("Failed to create devices:", err) } log.Debug("chroot", rootDir, command) if err := syscall.Chroot(rootDir); err != nil { return fmt.Errorf("Failed to chroot:", err) } if err := syscall.Chdir("/"); err != nil { return fmt.Errorf("Failed to chdir /:", err) } if !c.Bool("no-dropcaps") { log.Debug("drop capabilities") if err := osutil.DropCapabilities(keepCaps); err != nil { return fmt.Errorf("Failed to drop capabilities:", err) } } log.Debug("setgid", gid) if err := osutil.Setgid(gid); err != nil { return fmt.Errorf("Failed to set group %d:", gid, err) } log.Debug("setuid", uid) if err := osutil.Setuid(uid); err != nil { return fmt.Errorf("Failed to set user %d:", uid, err) } return osutil.Execv(command[0], command[0:], os.Environ()) }
func Remount(directory, options string) error { return mount.Mount("", directory, "", fmt.Sprintf("remount,%s", options)) }