mirror of
https://github.com/clearlinux/docker.git
synced 2026-09-06 21:51:33 +00:00
Improve interface by moving to subpkg
Enable builds on OSX
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||
@@ -0,0 +1,5 @@
|
||||
package mount
|
||||
|
||||
func parseOptions(options string) (int, string) {
|
||||
panic("Not implemented")
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Parse fstab type mount options into mount() flags
|
||||
// and device specific data
|
||||
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, ",")
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Looks at /proc/self/mountinfo to determine of the specified
|
||||
// mountpoint has been mounted
|
||||
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
|
||||
}
|
||||
|
||||
// Mount the specified options at the target path
|
||||
// Options must be specified as fstab style
|
||||
func Mount(device, target, mType, options string) error {
|
||||
if mounted, err := Mounted(target); err != nil || mounted {
|
||||
return err
|
||||
}
|
||||
|
||||
flag, data := parseOptions(options)
|
||||
if err := mount(device, target, mType, uintptr(flag), data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Unmount the target only if it is mounted
|
||||
func Unmount(target string) (err error) {
|
||||
if mounted, err := Mounted(target); err != nil || !mounted {
|
||||
return err
|
||||
}
|
||||
|
||||
// Simple retry logic for unmount
|
||||
for i := 0; i < 10; i++ {
|
||||
if err = unmount(target, 0); err == nil {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package mount
|
||||
|
||||
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(), "mount-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()
|
||||
|
||||
if err := Mount(sourcePath, targetPath, "none", "bind,ro"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetPath); 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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package mount
|
||||
|
||||
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
panic("Not implemented")
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||
return syscall.Mount(device, target, mType, flag, data)
|
||||
}
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
return syscall.Unmount(target, flag)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
mountinfoFormat = "%d %d %d:%d %s %s %s - %s %s %s"
|
||||
)
|
||||
|
||||
// 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
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user