134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
|
package configs
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"syscall"
|
||
|
|
||
|
"github.com/docker/docker/pkg/symlink"
|
||
|
"github.com/docker/libcontainer/label"
|
||
|
)
|
||
|
|
||
|
const DefaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
|
||
|
|
||
|
type Mount struct {
|
||
|
Type string `json:"type,omitempty"`
|
||
|
Source string `json:"source,omitempty"` // Source path, in the host namespace
|
||
|
Destination string `json:"destination,omitempty"` // Destination path, in the container
|
||
|
Writable bool `json:"writable,omitempty"`
|
||
|
Relabel string `json:"relabel,omitempty"` // Relabel source if set, "z" indicates shared, "Z" indicates unshared
|
||
|
Private bool `json:"private,omitempty"`
|
||
|
Slave bool `json:"slave,omitempty"`
|
||
|
}
|
||
|
|
||
|
func (m *Mount) Mount(rootfs, mountLabel string) error {
|
||
|
switch m.Type {
|
||
|
case "bind":
|
||
|
return m.bindMount(rootfs, mountLabel)
|
||
|
case "tmpfs":
|
||
|
return m.tmpfsMount(rootfs, mountLabel)
|
||
|
default:
|
||
|
return fmt.Errorf("unsupported mount type %s for %s", m.Type, m.Destination)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (m *Mount) bindMount(rootfs, mountLabel string) error {
|
||
|
var (
|
||
|
flags = syscall.MS_BIND | syscall.MS_REC
|
||
|
dest = filepath.Join(rootfs, m.Destination)
|
||
|
)
|
||
|
|
||
|
if !m.Writable {
|
||
|
flags = flags | syscall.MS_RDONLY
|
||
|
}
|
||
|
|
||
|
if m.Slave {
|
||
|
flags = flags | syscall.MS_SLAVE
|
||
|
}
|
||
|
|
||
|
stat, err := os.Stat(m.Source)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// FIXME: (crosbymichael) This does not belong here and should be done a layer above
|
||
|
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, mountLabel, m.Relabel); err != nil {
|
||
|
return fmt.Errorf("relabeling %s to %s %s", m.Source, 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
|
||
|
}
|
||
|
|
||
|
func (m *Mount) tmpfsMount(rootfs, mountLabel string) error {
|
||
|
var (
|
||
|
err error
|
||
|
l = label.FormatMountLabel("", mountLabel)
|
||
|
dest = filepath.Join(rootfs, m.Destination)
|
||
|
)
|
||
|
|
||
|
// FIXME: (crosbymichael) This does not belong here and should be done a layer above
|
||
|
if dest, err = symlink.FollowSymlinkInScope(dest, rootfs); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if err := createIfNotExists(dest, true); err != nil {
|
||
|
return fmt.Errorf("creating new tmpfs mount target %s", err)
|
||
|
}
|
||
|
|
||
|
if err := syscall.Mount("tmpfs", dest, "tmpfs", uintptr(DefaultMountFlags), l); err != nil {
|
||
|
return fmt.Errorf("%s mounting %s in tmpfs", err, dest)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func createIfNotExists(path string, isDir bool) error {
|
||
|
if _, err := os.Stat(path); err != nil {
|
||
|
if os.IsNotExist(err) {
|
||
|
if isDir {
|
||
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
} else {
|
||
|
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
f, err := os.OpenFile(path, os.O_CREATE, 0755)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
f.Close()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|