Exemple #1
0
func setupBindmounts(rootfs string, mountConfig *MountConfig) error {
	bindMounts := mountConfig.Mounts
	for _, m := range bindMounts.OfType("bind") {
		var (
			flags = syscall.MS_BIND | syscall.MS_REC
			dest  = filepath.Join(rootfs, m.Destination)
		)
		if !m.Writable {
			flags = flags | syscall.MS_RDONLY
		}

		stat, err := os.Stat(m.Source)
		if err != nil {
			return err
		}

		dest, err = symlink.FollowSymlinkInScope(dest, rootfs)
		if err != nil {
			return err
		}

		if err := createIfNotExists(dest, stat.IsDir()); err != nil {
			return fmt.Errorf("Creating new bind-mount target, %s", err)
		}

		if err := syscall.Mount(m.Source, dest, "bind", uintptr(flags), ""); err != nil {
			return fmt.Errorf("mounting %s into %s %s", m.Source, dest, err)
		}
		if !m.Writable {
			if err := syscall.Mount(m.Source, dest, "bind", uintptr(flags|syscall.MS_REMOUNT), ""); err != nil {
				return fmt.Errorf("remounting %s into %s %s", m.Source, dest, err)
			}
		}
		if m.Relabel != "" {
			if err := label.Relabel(m.Source, mountConfig.MountLabel, m.Relabel); err != nil {
				return fmt.Errorf("relabeling %s to %s %s", m.Source, mountConfig.MountLabel, err)
			}
		}
		if m.Private {
			if err := syscall.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil {
				return fmt.Errorf("mounting %s private %s", dest, err)
			}
		}
	}
	return nil
}
Exemple #2
0
func (container *Container) Copy(resource string) (io.ReadCloser, error) {
	if err := container.Mount(); err != nil {
		return nil, err
	}

	var filter []string

	resPath := container.getResourcePath(resource)
	basePath, err := symlink.FollowSymlinkInScope(resPath, container.basefs)
	if err != nil {
		container.Unmount()
		return nil, err
	}

	stat, err := os.Stat(basePath)
	if err != nil {
		container.Unmount()
		return nil, err
	}
	if !stat.IsDir() {
		d, f := path.Split(basePath)
		basePath = d
		filter = []string{f}
	} else {
		filter = []string{path.Base(basePath)}
		basePath = path.Dir(basePath)
	}

	archive, err := archive.TarFilter(basePath, &archive.TarOptions{
		Compression: archive.Uncompressed,
		Includes:    filter,
	})
	if err != nil {
		container.Unmount()
		return nil, err
	}
	return utils.NewReadCloserWrapper(archive, func() error {
			err := archive.Close()
			container.Unmount()
			return err
		}),
		nil
}
func (b *buildFile) addContext(container *daemon.Container, orig, dest string, remote bool) error {
	var (
		err        error
		destExists = true
		origPath   = path.Join(b.contextPath, orig)
		destPath   = path.Join(container.RootfsPath(), dest)
	)

	if destPath != container.RootfsPath() {
		destPath, err = symlink.FollowSymlinkInScope(destPath, container.RootfsPath())
		if err != nil {
			return err
		}
	}

	// Preserve the trailing '/'
	if strings.HasSuffix(dest, "/") {
		destPath = destPath + "/"
	}
	destStat, err := os.Stat(destPath)
	if err != nil {
		if os.IsNotExist(err) {
			destExists = false
		} else {
			return err
		}
	}
	fi, err := os.Stat(origPath)
	if err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("%s: no such file or directory", orig)
		}
		return err
	}

	fixPermsR := func(destPath string, uid, gid int) error {
		return filepath.Walk(destPath, func(path string, info os.FileInfo, err error) error {
			if err := os.Lchown(path, uid, gid); err != nil && !os.IsNotExist(err) {
				return err
			}
			return nil
		})
	}

	if fi.IsDir() {
		if err := archive.CopyWithTar(origPath, destPath); err != nil {
			return err
		}
		if destExists {
			files, err := ioutil.ReadDir(origPath)
			if err != nil {
				return err
			}
			for _, file := range files {
				if err := fixPermsR(filepath.Join(destPath, file.Name()), 0, 0); err != nil {
					return err
				}
			}
		} else {
			if err := fixPermsR(destPath, 0, 0); err != nil {
				return err
			}
		}
		return nil
	}

	// First try to unpack the source as an archive
	// to support the untar feature we need to clean up the path a little bit
	// because tar is very forgiving.  First we need to strip off the archive's
	// filename from the path but this is only added if it does not end in / .
	tarDest := destPath
	if strings.HasSuffix(tarDest, "/") {
		tarDest = filepath.Dir(destPath)
	}

	// If we are adding a remote file, do not try to untar it
	if !remote {
		// try to successfully untar the orig
		if err := archive.UntarPath(origPath, tarDest); err == nil {
			return nil
		}
		utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
	}

	// If that fails, just copy it as a regular file
	// but do not use all the magic path handling for the tar path
	if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
		return err
	}
	if err := archive.CopyWithTar(origPath, destPath); err != nil {
		return err
	}

	resPath := destPath
	if destExists && destStat.IsDir() {
		resPath = path.Join(destPath, path.Base(origPath))
	}

	if err := fixPermsR(resPath, 0, 0); err != nil {
		return err
	}
	return nil
}
Exemple #4
0
func (container *Container) getRootResourcePath(path string) (string, error) {
	cleanPath := filepath.Join("/", path)
	return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
}
Exemple #5
0
func (b *buildFile) addContext(container *daemon.Container, orig, dest string, decompress bool) error {
	var (
		err        error
		destExists = true
		origPath   = path.Join(b.contextPath, orig)
		destPath   = path.Join(container.RootfsPath(), dest)
	)

	if destPath != container.RootfsPath() {
		destPath, err = symlink.FollowSymlinkInScope(destPath, container.RootfsPath())
		if err != nil {
			return err
		}
	}

	// Preserve the trailing '/'
	if strings.HasSuffix(dest, "/") || dest == "." {
		destPath = destPath + "/"
	}

	destStat, err := os.Stat(destPath)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		destExists = false
	}

	fi, err := os.Stat(origPath)
	if err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("%s: no such file or directory", orig)
		}
		return err
	}

	if fi.IsDir() {
		return copyAsDirectory(origPath, destPath, destExists)
	}

	// If we are adding a remote file (or we've been told not to decompress), do not try to untar it
	if decompress {
		// First try to unpack the source as an archive
		// to support the untar feature we need to clean up the path a little bit
		// because tar is very forgiving.  First we need to strip off the archive's
		// filename from the path but this is only added if it does not end in / .
		tarDest := destPath
		if strings.HasSuffix(tarDest, "/") {
			tarDest = filepath.Dir(destPath)
		}

		// try to successfully untar the orig
		if err := archive.UntarPath(origPath, tarDest); err == nil {
			return nil
		} else if err != io.EOF {
			utils.Debugf("Couldn't untar %s to %s: %s", origPath, tarDest, err)
		}
	}

	if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
		return err
	}
	if err := archive.CopyWithTar(origPath, destPath); err != nil {
		return err
	}

	resPath := destPath
	if destExists && destStat.IsDir() {
		resPath = path.Join(destPath, path.Base(origPath))
	}

	return fixPermissions(resPath, 0, 0)
}
Exemple #6
0
func createVolumes(container *Container) error {
	binds, err := getBindMap(container)
	if err != nil {
		return err
	}

	volumesDriver := container.daemon.volumes.Driver()
	// Create the requested volumes if they don't exist
	for volPath := range container.Config.Volumes {
		volPath = filepath.Clean(volPath)
		volIsDir := true
		// Skip existing volumes
		if _, exists := container.Volumes[volPath]; exists {
			continue
		}
		var srcPath string
		var isBindMount bool
		srcRW := false
		// If an external bind is defined for this volume, use that as a source
		if bindMap, exists := binds[volPath]; exists {
			isBindMount = true
			srcPath = bindMap.SrcPath
			if !filepath.IsAbs(srcPath) {
				return fmt.Errorf("%s must be an absolute path", srcPath)
			}
			if strings.ToLower(bindMap.Mode) == "rw" {
				srcRW = true
			}
			if stat, err := os.Stat(bindMap.SrcPath); err != nil {
				return err
			} else {
				volIsDir = stat.IsDir()
			}
			// Otherwise create an directory in $ROOT/volumes/ and use that
		} else {

			// Do not pass a container as the parameter for the volume creation.
			// The graph driver using the container's information ( Image ) to
			// create the parent.
			c, err := container.daemon.volumes.Create(nil, "", "", "", "", nil, nil)
			if err != nil {
				return err
			}
			srcPath, err = volumesDriver.Get(c.ID, "")
			if err != nil {
				return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
			}
			srcRW = true // RW by default
		}

		if p, err := filepath.EvalSymlinks(srcPath); err != nil {
			return err
		} else {
			srcPath = p
		}

		// Create the mountpoint
		rootVolPath, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, volPath), container.basefs)
		if err != nil {
			return err
		}

		newVolPath, err := filepath.Rel(container.basefs, rootVolPath)
		if err != nil {
			return err
		}
		newVolPath = "/" + newVolPath

		if volPath != newVolPath {
			delete(container.Volumes, volPath)
			delete(container.VolumesRW, volPath)
		}

		container.Volumes[newVolPath] = srcPath
		container.VolumesRW[newVolPath] = srcRW

		if err := createIfNotExists(rootVolPath, volIsDir); err != nil {
			return err
		}

		// Do not copy or change permissions if we are mounting from the host
		if srcRW && !isBindMount {
			volList, err := ioutil.ReadDir(rootVolPath)
			if err != nil {
				return err
			}
			if len(volList) > 0 {
				srcList, err := ioutil.ReadDir(srcPath)
				if err != nil {
					return err
				}
				if len(srcList) == 0 {
					// If the source volume is empty copy files from the root into the volume
					if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
						return err
					}
				}
			}

			var stat syscall.Stat_t
			if err := syscall.Stat(rootVolPath, &stat); err != nil {
				return err
			}
			var srcStat syscall.Stat_t
			if err := syscall.Stat(srcPath, &srcStat); err != nil {
				return err
			}
			// Change the source volume's ownership if it differs from the root
			// files that were just copied
			if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
				if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
func initializeVolume(container *Container, volPath string, binds map[string]BindMap) error {
	volumesDriver := container.daemon.volumes.Driver()
	volPath = filepath.Clean(volPath)
	// Skip existing volumes
	if _, exists := container.Volumes[volPath]; exists {
		return nil
	}

	var (
		srcPath     string
		isBindMount bool
		volIsDir    = true

		srcRW = false
	)

	// If an external bind is defined for this volume, use that as a source
	if bindMap, exists := binds[volPath]; exists {
		isBindMount = true
		srcPath = bindMap.SrcPath
		if !filepath.IsAbs(srcPath) {
			return fmt.Errorf("%s must be an absolute path", srcPath)
		}
		if strings.ToLower(bindMap.Mode) == "rw" {
			srcRW = true
		}
		if stat, err := os.Stat(bindMap.SrcPath); err != nil {
			return err
		} else {
			volIsDir = stat.IsDir()
		}
		// Otherwise create an directory in $ROOT/volumes/ and use that
	} else {
		// Do not pass a container as the parameter for the volume creation.
		// The graph driver using the container's information ( Image ) to
		// create the parent.
		c, err := container.daemon.volumes.Create(nil, "", "", "", "", nil, nil)
		if err != nil {
			return err
		}
		srcPath, err = volumesDriver.Get(c.ID, "")
		if err != nil {
			return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
		}
		srcRW = true // RW by default
	}

	if p, err := filepath.EvalSymlinks(srcPath); err != nil {
		return err
	} else {
		srcPath = p
	}

	// Create the mountpoint
	rootVolPath, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, volPath), container.basefs)
	if err != nil {
		return err
	}

	newVolPath, err := filepath.Rel(container.basefs, rootVolPath)
	if err != nil {
		return err
	}
	newVolPath = "/" + newVolPath

	if volPath != newVolPath {
		delete(container.Volumes, volPath)
		delete(container.VolumesRW, volPath)
	}

	container.Volumes[newVolPath] = srcPath
	container.VolumesRW[newVolPath] = srcRW

	if err := createIfNotExists(rootVolPath, volIsDir); err != nil {
		return err
	}

	// Do not copy or change permissions if we are mounting from the host
	if srcRW && !isBindMount {
		if err := copyExistingContents(rootVolPath, srcPath); err != nil {
			return err
		}
	}
	return nil
}