mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Support FreeBSD on pkg/mount
Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi <kato.kazuyoshi@gmail.com> (github: kzys)
This commit is contained in:
		
							parent
							
								
									ca7a0e6d6e
								
							
						
					
					
						commit
						3754fdd7ca
					
				
					 12 changed files with 312 additions and 137 deletions
				
			
		
							
								
								
									
										62
									
								
								pkg/mount/flags.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								pkg/mount/flags.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
package mount
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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, RDONLY},
 | 
			
		||||
		"rw":            {true, RDONLY},
 | 
			
		||||
		"suid":          {true, NOSUID},
 | 
			
		||||
		"nosuid":        {false, NOSUID},
 | 
			
		||||
		"dev":           {true, NODEV},
 | 
			
		||||
		"nodev":         {false, NODEV},
 | 
			
		||||
		"exec":          {true, NOEXEC},
 | 
			
		||||
		"noexec":        {false, NOEXEC},
 | 
			
		||||
		"sync":          {false, SYNCHRONOUS},
 | 
			
		||||
		"async":         {true, SYNCHRONOUS},
 | 
			
		||||
		"dirsync":       {false, DIRSYNC},
 | 
			
		||||
		"remount":       {false, REMOUNT},
 | 
			
		||||
		"mand":          {false, MANDLOCK},
 | 
			
		||||
		"nomand":        {true, MANDLOCK},
 | 
			
		||||
		"atime":         {true, NOATIME},
 | 
			
		||||
		"noatime":       {false, NOATIME},
 | 
			
		||||
		"diratime":      {true, NODIRATIME},
 | 
			
		||||
		"nodiratime":    {false, NODIRATIME},
 | 
			
		||||
		"bind":          {false, BIND},
 | 
			
		||||
		"rbind":         {false, RBIND},
 | 
			
		||||
		"private":       {false, PRIVATE},
 | 
			
		||||
		"relatime":      {false, RELATIME},
 | 
			
		||||
		"norelatime":    {true, RELATIME},
 | 
			
		||||
		"strictatime":   {false, STRICTATIME},
 | 
			
		||||
		"nostrictatime": {true, STRICTATIME},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, o := range strings.Split(options, ",") {
 | 
			
		||||
		// If the option does not exist in the flags table or the flag
 | 
			
		||||
		// is not supported on the platform,
 | 
			
		||||
		// then it is a data value for a specific fs type
 | 
			
		||||
		if f, exists := flags[o]; exists && f.flag != 0 {
 | 
			
		||||
			if f.clear {
 | 
			
		||||
				flag &= ^f.flag
 | 
			
		||||
			} else {
 | 
			
		||||
				flag |= f.flag
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			data = append(data, o)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return flag, strings.Join(data, ",")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								pkg/mount/flags_freebsd.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/mount/flags_freebsd.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
// +build freebsd,cgo
 | 
			
		||||
 | 
			
		||||
package mount
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#include <sys/mount.h>
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	RDONLY      = C.MNT_RDONLY
 | 
			
		||||
	NOSUID      = C.MNT_NOSUID
 | 
			
		||||
	NOEXEC      = C.MNT_NOEXEC
 | 
			
		||||
	SYNCHRONOUS = C.MNT_SYNCHRONOUS
 | 
			
		||||
	NOATIME     = C.MNT_NOATIME
 | 
			
		||||
 | 
			
		||||
	BIND        = 0
 | 
			
		||||
	DIRSYNC     = 0
 | 
			
		||||
	MANDLOCK    = 0
 | 
			
		||||
	NODEV       = 0
 | 
			
		||||
	NODIRATIME  = 0
 | 
			
		||||
	PRIVATE     = 0
 | 
			
		||||
	RBIND       = 0
 | 
			
		||||
	RELATIVE    = 0
 | 
			
		||||
	RELATIME    = 0
 | 
			
		||||
	REMOUNT     = 0
 | 
			
		||||
	STRICTATIME = 0
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -3,62 +3,23 @@
 | 
			
		|||
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},
 | 
			
		||||
		"private":       {false, syscall.MS_PRIVATE},
 | 
			
		||||
		"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, ",")
 | 
			
		||||
}
 | 
			
		||||
const (
 | 
			
		||||
	RDONLY      = syscall.MS_RDONLY
 | 
			
		||||
	NOSUID      = syscall.MS_NOSUID
 | 
			
		||||
	NODEV       = syscall.MS_NODEV
 | 
			
		||||
	NOEXEC      = syscall.MS_NOEXEC
 | 
			
		||||
	SYNCHRONOUS = syscall.MS_SYNCHRONOUS
 | 
			
		||||
	DIRSYNC     = syscall.MS_DIRSYNC
 | 
			
		||||
	REMOUNT     = syscall.MS_REMOUNT
 | 
			
		||||
	MANDLOCK    = syscall.MS_MANDLOCK
 | 
			
		||||
	NOATIME     = syscall.MS_NOATIME
 | 
			
		||||
	NODIRATIME  = syscall.MS_NODIRATIME
 | 
			
		||||
	BIND        = syscall.MS_BIND
 | 
			
		||||
	RBIND       = syscall.MS_BIND | syscall.MS_REC
 | 
			
		||||
	PRIVATE     = syscall.MS_PRIVATE
 | 
			
		||||
	RELATIME    = syscall.MS_RELATIME
 | 
			
		||||
	STRICTATIME = syscall.MS_STRICTATIME
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,22 @@
 | 
			
		|||
// +build !linux !amd64
 | 
			
		||||
// +build !linux,!freebsd linux,!amd64 freebsd,!cgo
 | 
			
		||||
 | 
			
		||||
package mount
 | 
			
		||||
 | 
			
		||||
func parseOptions(options string) (int, string) {
 | 
			
		||||
	panic("Not implemented")
 | 
			
		||||
}
 | 
			
		||||
const (
 | 
			
		||||
	BIND        = 0
 | 
			
		||||
	DIRSYNC     = 0
 | 
			
		||||
	MANDLOCK    = 0
 | 
			
		||||
	NOATIME     = 0
 | 
			
		||||
	NODEV       = 0
 | 
			
		||||
	NODIRATIME  = 0
 | 
			
		||||
	NOEXEC      = 0
 | 
			
		||||
	NOSUID      = 0
 | 
			
		||||
	PRIVATE     = 0
 | 
			
		||||
	RBIND       = 0
 | 
			
		||||
	RELATIME    = 0
 | 
			
		||||
	RELATIVE    = 0
 | 
			
		||||
	REMOUNT     = 0
 | 
			
		||||
	STRICTATIME = 0
 | 
			
		||||
	SYNCHRONOUS = 0
 | 
			
		||||
	RDONLY      = 0
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,12 +3,11 @@ package mount
 | 
			
		|||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestMountOptionsParsing(t *testing.T) {
 | 
			
		||||
	options := "bind,ro,size=10k"
 | 
			
		||||
	options := "noatime,ro,size=10k"
 | 
			
		||||
 | 
			
		||||
	flag, data := parseOptions(options)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +15,7 @@ func TestMountOptionsParsing(t *testing.T) {
 | 
			
		|||
		t.Fatalf("Expected size=10 got %s", data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedFlag := syscall.MS_BIND | syscall.MS_RDONLY
 | 
			
		||||
	expectedFlag := NOATIME | RDONLY
 | 
			
		||||
 | 
			
		||||
	if flag != expectedFlag {
 | 
			
		||||
		t.Fatalf("Expected %d got %d", expectedFlag, flag)
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +107,7 @@ func TestMountReadonly(t *testing.T) {
 | 
			
		|||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := Unmount(targetPath); err != nil {
 | 
			
		||||
		if err := Unmount(targetDir); err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										59
									
								
								pkg/mount/mounter_freebsd.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								pkg/mount/mounter_freebsd.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
package mount
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/_iovec.h>
 | 
			
		||||
#include <sys/mount.h>
 | 
			
		||||
#include <sys/param.h>
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func allocateIOVecs(options []string) []C.struct_iovec {
 | 
			
		||||
	out := make([]C.struct_iovec, len(options))
 | 
			
		||||
	for i, option := range options {
 | 
			
		||||
		out[i].iov_base = unsafe.Pointer(C.CString(option))
 | 
			
		||||
		out[i].iov_len = C.size_t(len(option) + 1)
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mount(device, target, mType string, flag uintptr, data string) error {
 | 
			
		||||
	isNullFS := false
 | 
			
		||||
 | 
			
		||||
	xs := strings.Split(data, ",")
 | 
			
		||||
	for _, x := range xs {
 | 
			
		||||
		if x == "bind" {
 | 
			
		||||
			isNullFS = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	options := []string{"fspath", target}
 | 
			
		||||
	if isNullFS {
 | 
			
		||||
		options = append(options, "fstype", "nullfs", "target", device)
 | 
			
		||||
	} else {
 | 
			
		||||
		options = append(options, "fstype", mType, "from", device)
 | 
			
		||||
	}
 | 
			
		||||
	rawOptions := allocateIOVecs(options)
 | 
			
		||||
	for _, rawOption := range rawOptions {
 | 
			
		||||
		defer C.free(rawOption.iov_base)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 {
 | 
			
		||||
		reason := C.GoString(C.strerror(*C.__error()))
 | 
			
		||||
		return fmt.Errorf("Failed to call nmount: %s", reason)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func unmount(target string, flag int) error {
 | 
			
		||||
	return syscall.Unmount(target, flag)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
// +build !linux !amd64
 | 
			
		||||
// +build !linux,!freebsd linux,!amd64 freebsd,!cgo
 | 
			
		||||
 | 
			
		||||
package mount
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,79 +1,7 @@
 | 
			
		|||
package mount
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
 | 
			
		||||
	   (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)
 | 
			
		||||
 | 
			
		||||
	   (1) mount ID:  unique identifier of the mount (may be reused after umount)
 | 
			
		||||
	   (2) parent ID:  ID of parent (or of self for the top of the mount tree)
 | 
			
		||||
	   (3) major:minor:  value of st_dev for files on filesystem
 | 
			
		||||
	   (4) root:  root of the mount within the filesystem
 | 
			
		||||
	   (5) mount point:  mount point relative to the process's root
 | 
			
		||||
	   (6) mount options:  per mount options
 | 
			
		||||
	   (7) optional fields:  zero or more fields of the form "tag[:value]"
 | 
			
		||||
	   (8) separator:  marks the end of the optional fields
 | 
			
		||||
	   (9) filesystem type:  name of filesystem of the form "type[.subtype]"
 | 
			
		||||
	   (10) mount source:  filesystem specific information or "none"
 | 
			
		||||
	   (11) super options:  per super block options*/
 | 
			
		||||
	mountinfoFormat = "%d %d %d:%d %s %s %s "
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MountInfo struct {
 | 
			
		||||
	Id, Parent, Major, Minor int
 | 
			
		||||
	Root, Mountpoint, Opts   string
 | 
			
		||||
	Fstype, Source, VfsOpts  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
 | 
			
		||||
func parseMountTable() ([]*MountInfo, error) {
 | 
			
		||||
	f, err := os.Open("/proc/self/mountinfo")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	return parseInfoFile(f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseInfoFile(r io.Reader) ([]*MountInfo, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		s   = bufio.NewScanner(r)
 | 
			
		||||
		out = []*MountInfo{}
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for s.Scan() {
 | 
			
		||||
		if err := s.Err(); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var (
 | 
			
		||||
			p    = &MountInfo{}
 | 
			
		||||
			text = s.Text()
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		if _, err := fmt.Sscanf(text, mountinfoFormat,
 | 
			
		||||
			&p.Id, &p.Parent, &p.Major, &p.Minor,
 | 
			
		||||
			&p.Root, &p.Mountpoint, &p.Opts); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
 | 
			
		||||
		}
 | 
			
		||||
		// Safe as mountinfo encodes mountpoints with spaces as \040.
 | 
			
		||||
		index := strings.Index(text, " - ")
 | 
			
		||||
		postSeparatorFields := strings.Fields(text[index+3:])
 | 
			
		||||
		if len(postSeparatorFields) != 3 {
 | 
			
		||||
			return nil, fmt.Errorf("Error did not find 3 fields post '-' in '%s'", text)
 | 
			
		||||
		}
 | 
			
		||||
		p.Fstype = postSeparatorFields[0]
 | 
			
		||||
		p.Source = postSeparatorFields[1]
 | 
			
		||||
		p.VfsOpts = postSeparatorFields[2]
 | 
			
		||||
		out = append(out, p)
 | 
			
		||||
	}
 | 
			
		||||
	return out, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										38
									
								
								pkg/mount/mountinfo_freebsd.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								pkg/mount/mountinfo_freebsd.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
package mount
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#include <sys/param.h>
 | 
			
		||||
#include <sys/ucred.h>
 | 
			
		||||
#include <sys/mount.h>
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
 | 
			
		||||
func parseMountTable() ([]*MountInfo, error) {
 | 
			
		||||
	var rawEntries *C.struct_statfs
 | 
			
		||||
 | 
			
		||||
	count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
 | 
			
		||||
	if count == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("Failed to call getmntinfo")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var entries []C.struct_statfs
 | 
			
		||||
	header := (*reflect.SliceHeader)(unsafe.Pointer(&entries))
 | 
			
		||||
	header.Cap = count
 | 
			
		||||
	header.Len = count
 | 
			
		||||
	header.Data = uintptr(unsafe.Pointer(rawEntries))
 | 
			
		||||
 | 
			
		||||
	var out []*MountInfo
 | 
			
		||||
	for _, entry := range entries {
 | 
			
		||||
		var mountinfo MountInfo
 | 
			
		||||
		mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
 | 
			
		||||
		out = append(out, &mountinfo)
 | 
			
		||||
	}
 | 
			
		||||
	return out, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								pkg/mount/mountinfo_linux.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								pkg/mount/mountinfo_linux.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,73 @@
 | 
			
		|||
package mount
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
 | 
			
		||||
	   (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)
 | 
			
		||||
 | 
			
		||||
	   (1) mount ID:  unique identifier of the mount (may be reused after umount)
 | 
			
		||||
	   (2) parent ID:  ID of parent (or of self for the top of the mount tree)
 | 
			
		||||
	   (3) major:minor:  value of st_dev for files on filesystem
 | 
			
		||||
	   (4) root:  root of the mount within the filesystem
 | 
			
		||||
	   (5) mount point:  mount point relative to the process's root
 | 
			
		||||
	   (6) mount options:  per mount options
 | 
			
		||||
	   (7) optional fields:  zero or more fields of the form "tag[:value]"
 | 
			
		||||
	   (8) separator:  marks the end of the optional fields
 | 
			
		||||
	   (9) filesystem type:  name of filesystem of the form "type[.subtype]"
 | 
			
		||||
	   (10) mount source:  filesystem specific information or "none"
 | 
			
		||||
	   (11) super options:  per super block options*/
 | 
			
		||||
	mountinfoFormat = "%d %d %d:%d %s %s %s "
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
 | 
			
		||||
func parseMountTable() ([]*MountInfo, error) {
 | 
			
		||||
	f, err := os.Open("/proc/self/mountinfo")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	return parseInfoFile(f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseInfoFile(r io.Reader) ([]*MountInfo, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		s   = bufio.NewScanner(r)
 | 
			
		||||
		out = []*MountInfo{}
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for s.Scan() {
 | 
			
		||||
		if err := s.Err(); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var (
 | 
			
		||||
			p    = &MountInfo{}
 | 
			
		||||
			text = s.Text()
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		if _, err := fmt.Sscanf(text, mountinfoFormat,
 | 
			
		||||
			&p.Id, &p.Parent, &p.Major, &p.Minor,
 | 
			
		||||
			&p.Root, &p.Mountpoint, &p.Opts); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
 | 
			
		||||
		}
 | 
			
		||||
		// Safe as mountinfo encodes mountpoints with spaces as \040.
 | 
			
		||||
		index := strings.Index(text, " - ")
 | 
			
		||||
		postSeparatorFields := strings.Fields(text[index+3:])
 | 
			
		||||
		if len(postSeparatorFields) != 3 {
 | 
			
		||||
			return nil, fmt.Errorf("Error did not find 3 fields post '-' in '%s'", text)
 | 
			
		||||
		}
 | 
			
		||||
		p.Fstype = postSeparatorFields[0]
 | 
			
		||||
		p.Source = postSeparatorFields[1]
 | 
			
		||||
		p.VfsOpts = postSeparatorFields[2]
 | 
			
		||||
		out = append(out, p)
 | 
			
		||||
	}
 | 
			
		||||
	return out, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								pkg/mount/mountinfo_unsupported.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								pkg/mount/mountinfo_unsupported.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
// +build !linux,!freebsd freebsd,!cgo
 | 
			
		||||
 | 
			
		||||
package mount
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func parseMountTable() ([]*MountInfo, error) {
 | 
			
		||||
	return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue