Improve interface by moving to subpkg

Enable builds on OSX
This commit is contained in:
Michael Crosby
2013-12-18 16:42:49 -08:00
parent a6fdc5d208
commit 7bc96aec7b
12 changed files with 243 additions and 227 deletions
+2 -1
View File
@@ -25,6 +25,7 @@ import (
"fmt"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/graphdriver"
mountpk "github.com/dotcloud/docker/mount"
"github.com/dotcloud/docker/utils"
"os"
"os/exec"
@@ -295,7 +296,7 @@ func (a *Driver) unmount(id string) error {
func (a *Driver) mounted(id string) (bool, error) {
target := path.Join(a.rootPath(), "mnt", id)
return graphdriver.Mounted(target)
return mountpk.Mounted(target)
}
// During cleanup aufs needs to unmount all mountpoints
-147
View File
@@ -1,19 +1,13 @@
package graphdriver
import (
"bufio"
"fmt"
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/utils"
"os"
"path"
"strings"
"syscall"
"time"
)
const mountinfoFormat = "%d %d %d:%d %s %s %s - %s %s %s"
type InitFunc func(root string) (Driver, error)
type Driver interface {
@@ -37,13 +31,6 @@ type Differ interface {
DiffSize(id string) (bytes int64, err error)
}
type Mount struct {
Device string
Target string
Type string
Options string
}
var (
DefaultDriver string
// All registred drivers
@@ -101,137 +88,3 @@ func New(root string) (driver Driver, err error) {
}
return nil, err
}
func (m *Mount) Mount(root string) error {
target := path.Join(root, m.Target)
if mounted, err := Mounted(target); err != nil || mounted {
return err
}
flag, data := parseOptions(m.Options)
if err := syscall.Mount(m.Device, target, m.Type, uintptr(flag), data); err != nil {
return err
}
return nil
}
func parseOptions(options string) (int, string) {
var (
flag int
data []string
)
flags := map[string]struct {
clear bool
flag int
}{
"defaults": {false, 0},
"ro": {false, syscall.MS_RDONLY},
"rw": {true, syscall.MS_RDONLY},
"suid": {true, syscall.MS_NOSUID},
"nosuid": {false, syscall.MS_NOSUID},
"dev": {true, syscall.MS_NODEV},
"nodev": {false, syscall.MS_NODEV},
"exec": {true, syscall.MS_NOEXEC},
"noexec": {false, syscall.MS_NOEXEC},
"sync": {false, syscall.MS_SYNCHRONOUS},
"async": {true, syscall.MS_SYNCHRONOUS},
"dirsync": {false, syscall.MS_DIRSYNC},
"remount": {false, syscall.MS_REMOUNT},
"mand": {false, syscall.MS_MANDLOCK},
"nomand": {true, syscall.MS_MANDLOCK},
"atime": {true, syscall.MS_NOATIME},
"noatime": {false, syscall.MS_NOATIME},
"diratime": {true, syscall.MS_NODIRATIME},
"nodiratime": {false, syscall.MS_NODIRATIME},
"bind": {false, syscall.MS_BIND},
"rbind": {false, syscall.MS_BIND | syscall.MS_REC},
"relatime": {false, syscall.MS_RELATIME},
"norelatime": {true, syscall.MS_RELATIME},
"strictatime": {false, syscall.MS_STRICTATIME},
"nostrictatime": {true, syscall.MS_STRICTATIME},
}
for _, o := range strings.Split(options, ",") {
// If the option does not exist in the flags table then it is a
// data value for a specific fs type
if f, exists := flags[o]; exists {
if f.clear {
flag &= ^f.flag
} else {
flag |= f.flag
}
} else {
data = append(data, o)
}
}
return flag, strings.Join(data, ",")
}
func (m *Mount) Unmount(root string) (err error) {
target := path.Join(root, m.Target)
if mounted, err := Mounted(target); err != nil || !mounted {
return err
}
// Simple retry logic for unmount
for i := 0; i < 10; i++ {
if err = syscall.Unmount(target, 0); err == nil {
return nil
}
utils.Debugf("[Unmount] %s", err)
time.Sleep(100 * time.Millisecond)
}
return
}
func Mounted(mountpoint string) (bool, error) {
entries, err := parseMountTable()
if err != nil {
return false, err
}
// Search the table for the mountpoint
for _, e := range entries {
if e.mountpoint == mountpoint {
return true, nil
}
}
return false, nil
}
// Represents one line from /proc/self/mountinfo
type procEntry struct {
id, parent, major, minor int
source, mountpoint, fstype, device string
vfsopts, opts string
}
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
//
// 180 20 0:2851 / /var/lib/docker/aufs/mnt/a22632d4ed3cb2438246064408f9f07734cbd331f50c81f1ca3dcbd78541ce83 rw,relatime - aufs none rw,si=e9663ac1adbdb4f8
func parseMountTable() ([]*procEntry, error) {
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return nil, err
}
defer f.Close()
s := bufio.NewScanner(f)
out := []*procEntry{}
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
p := &procEntry{}
if _, err := fmt.Sscanf(s.Text(), mountinfoFormat,
&p.id, &p.parent, &p.major, &p.minor,
&p.source, &p.mountpoint, &p.vfsopts, &p.fstype,
&p.device, &p.opts); err != nil {
return nil, err
}
out = append(out, p)
}
return out, nil
}
-74
View File
@@ -1,74 +0,0 @@
package graphdriver
import (
"os"
"path"
"syscall"
"testing"
)
func TestMountOptionsParsing(t *testing.T) {
options := "bind,ro,size=10k"
flag, data := parseOptions(options)
if data != "size=10k" {
t.Fatalf("Expected size=10 got %s", data)
}
expectedFlag := syscall.MS_BIND | syscall.MS_RDONLY
if flag != expectedFlag {
t.Fatalf("Expected %d got %d", expectedFlag, flag)
}
}
func TestMounted(t *testing.T) {
tmp := path.Join(os.TempDir(), "graphdriver-tests")
if err := os.MkdirAll(tmp, 0777); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
var (
sourcePath = path.Join(tmp, "sourcefile.txt")
targetPath = path.Join(tmp, "targetfile.txt")
)
f, err := os.Create(sourcePath)
if err != nil {
t.Fatal(err)
}
f.WriteString("hello")
f.Close()
f, err = os.Create(targetPath)
if err != nil {
t.Fatal(err)
}
f.Close()
mount := &Mount{
Device: sourcePath,
Target: targetPath,
Type: "none",
Options: "bind,ro",
}
if err := mount.Mount("/"); err != nil {
t.Fatal(err)
}
defer func() {
if err := mount.Unmount("/"); err != nil {
t.Fatal(err)
}
}()
mounted, err := Mounted(targetPath)
if err != nil {
t.Fatal(err)
}
if !mounted {
t.Fatalf("Expected %s to be mounted", targetPath)
}
}