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
 | 
					package mount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parse fstab type mount options into mount() flags
 | 
					const (
 | 
				
			||||||
// and device specific data
 | 
						RDONLY      = syscall.MS_RDONLY
 | 
				
			||||||
func parseOptions(options string) (int, string) {
 | 
						NOSUID      = syscall.MS_NOSUID
 | 
				
			||||||
	var (
 | 
						NODEV       = syscall.MS_NODEV
 | 
				
			||||||
		flag int
 | 
						NOEXEC      = syscall.MS_NOEXEC
 | 
				
			||||||
		data []string
 | 
						SYNCHRONOUS = syscall.MS_SYNCHRONOUS
 | 
				
			||||||
	)
 | 
						DIRSYNC     = syscall.MS_DIRSYNC
 | 
				
			||||||
 | 
						REMOUNT     = syscall.MS_REMOUNT
 | 
				
			||||||
	flags := map[string]struct {
 | 
						MANDLOCK    = syscall.MS_MANDLOCK
 | 
				
			||||||
		clear bool
 | 
						NOATIME     = syscall.MS_NOATIME
 | 
				
			||||||
		flag  int
 | 
						NODIRATIME  = syscall.MS_NODIRATIME
 | 
				
			||||||
	}{
 | 
						BIND        = syscall.MS_BIND
 | 
				
			||||||
		"defaults":      {false, 0},
 | 
						RBIND       = syscall.MS_BIND | syscall.MS_REC
 | 
				
			||||||
		"ro":            {false, syscall.MS_RDONLY},
 | 
						PRIVATE     = syscall.MS_PRIVATE
 | 
				
			||||||
		"rw":            {true, syscall.MS_RDONLY},
 | 
						RELATIME    = syscall.MS_RELATIME
 | 
				
			||||||
		"suid":          {true, syscall.MS_NOSUID},
 | 
						STRICTATIME = syscall.MS_STRICTATIME
 | 
				
			||||||
		"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, ",")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,22 @@
 | 
				
			||||||
// +build !linux !amd64
 | 
					// +build !linux,!freebsd linux,!amd64 freebsd,!cgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package mount
 | 
					package mount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func parseOptions(options string) (int, string) {
 | 
					const (
 | 
				
			||||||
	panic("Not implemented")
 | 
						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 (
 | 
					import (
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"syscall"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMountOptionsParsing(t *testing.T) {
 | 
					func TestMountOptionsParsing(t *testing.T) {
 | 
				
			||||||
	options := "bind,ro,size=10k"
 | 
						options := "noatime,ro,size=10k"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flag, data := parseOptions(options)
 | 
						flag, data := parseOptions(options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +15,7 @@ func TestMountOptionsParsing(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expected size=10 got %s", data)
 | 
							t.Fatalf("Expected size=10 got %s", data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expectedFlag := syscall.MS_BIND | syscall.MS_RDONLY
 | 
						expectedFlag := NOATIME | RDONLY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if flag != expectedFlag {
 | 
						if flag != expectedFlag {
 | 
				
			||||||
		t.Fatalf("Expected %d got %d", expectedFlag, flag)
 | 
							t.Fatalf("Expected %d got %d", expectedFlag, flag)
 | 
				
			||||||
| 
						 | 
					@ -108,7 +107,7 @@ func TestMountReadonly(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if err := Unmount(targetPath); err != nil {
 | 
							if err := Unmount(targetDir); err != nil {
 | 
				
			||||||
			t.Fatal(err)
 | 
								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
 | 
					package mount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,79 +1,7 @@
 | 
				
			||||||
package mount
 | 
					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 {
 | 
					type MountInfo struct {
 | 
				
			||||||
	Id, Parent, Major, Minor int
 | 
						Id, Parent, Major, Minor int
 | 
				
			||||||
	Root, Mountpoint, Opts   string
 | 
						Root, Mountpoint, Opts   string
 | 
				
			||||||
	Fstype, Source, VfsOpts  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