mountinfo: refactored
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
This commit is contained in:
parent
d5707d3ac7
commit
8cd218237b
@ -23,23 +23,18 @@ type Info struct {
|
||||
// Mountpoint indicates the mount point relative to the process's root.
|
||||
Mountpoint string
|
||||
|
||||
// Opts represents mount-specific options.
|
||||
Opts string
|
||||
// Options represents mount-specific options.
|
||||
Options string
|
||||
|
||||
// Optional represents optional fields.
|
||||
Optional string
|
||||
|
||||
// Fstype indicates the type of filesystem, such as EXT3.
|
||||
Fstype string
|
||||
// FSType indicates the type of filesystem, such as EXT3.
|
||||
FSType string
|
||||
|
||||
// Source indicates filesystem specific information or "none".
|
||||
Source string
|
||||
|
||||
// VfsOpts represents per super block options.
|
||||
VfsOpts string
|
||||
}
|
||||
|
||||
// GetMounts retrieves a list of mounts for the current running process.
|
||||
func GetMounts() ([]*Info, error) {
|
||||
return parseMountTable()
|
||||
// VFSOptions represents per super block options.
|
||||
VFSOptions string
|
||||
}
|
||||
|
@ -13,9 +13,8 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||
// bind mounts.
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
var rawEntries *C.struct_statfs
|
||||
|
||||
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
|
||||
@ -29,13 +28,18 @@ func parseMountTable() ([]*Info, error) {
|
||||
header.Len = count
|
||||
header.Data = uintptr(unsafe.Pointer(rawEntries))
|
||||
|
||||
var out []*Info
|
||||
var out []Info
|
||||
for _, entry := range entries {
|
||||
var mountinfo Info
|
||||
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
|
||||
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
||||
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
|
||||
out = append(out, &mountinfo)
|
||||
mountinfo.FSType = C.GoString(&entry.f_fstypename[0])
|
||||
out = append(out, mountinfo)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PID collects the mounts for a specific process ID.
|
||||
func PID(pid int) ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.PID is not implemented on freebsd")
|
||||
}
|
||||
|
@ -28,9 +28,8 @@ const (
|
||||
mountinfoFormat = "%d %d %d:%d %s %s %s %s"
|
||||
)
|
||||
|
||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||
// bind mounts
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -40,10 +39,10 @@ func parseMountTable() ([]*Info, error) {
|
||||
return parseInfoFile(f)
|
||||
}
|
||||
|
||||
func parseInfoFile(r io.Reader) ([]*Info, error) {
|
||||
func parseInfoFile(r io.Reader) ([]Info, error) {
|
||||
var (
|
||||
s = bufio.NewScanner(r)
|
||||
out = []*Info{}
|
||||
out = []Info{}
|
||||
)
|
||||
|
||||
for s.Scan() {
|
||||
@ -52,14 +51,14 @@ func parseInfoFile(r io.Reader) ([]*Info, error) {
|
||||
}
|
||||
|
||||
var (
|
||||
p = &Info{}
|
||||
p = Info{}
|
||||
text = s.Text()
|
||||
optionalFields string
|
||||
)
|
||||
|
||||
if _, err := fmt.Sscanf(text, mountinfoFormat,
|
||||
&p.ID, &p.Parent, &p.Major, &p.Minor,
|
||||
&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
|
||||
&p.Root, &p.Mountpoint, &p.Options, &optionalFields); err != nil {
|
||||
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
|
||||
}
|
||||
// Safe as mountinfo encodes mountpoints with spaces as \040.
|
||||
@ -73,18 +72,18 @@ func parseInfoFile(r io.Reader) ([]*Info, error) {
|
||||
p.Optional = optionalFields
|
||||
}
|
||||
|
||||
p.Fstype = postSeparatorFields[0]
|
||||
p.FSType = postSeparatorFields[0]
|
||||
p.Source = postSeparatorFields[1]
|
||||
p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
|
||||
p.VFSOptions = strings.Join(postSeparatorFields[2:], " ")
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PidMountInfo collects the mounts for a specific process ID. If the process
|
||||
// ID is unknown, it is better to use `GetMounts` which will inspect
|
||||
// PID collects the mounts for a specific process ID. If the process
|
||||
// ID is unknown, it is better to use `Self` which will inspect
|
||||
// "/proc/self/mountinfo" instead.
|
||||
func PidMountInfo(pid int) ([]*Info, error) {
|
||||
func PID(pid int) ([]Info, error) {
|
||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -463,14 +463,14 @@ func TestParseFedoraMountinfoFields(t *testing.T) {
|
||||
Minor: 3,
|
||||
Root: "/",
|
||||
Mountpoint: "/proc",
|
||||
Opts: "rw,nosuid,nodev,noexec,relatime",
|
||||
Options: "rw,nosuid,nodev,noexec,relatime",
|
||||
Optional: "shared:5",
|
||||
Fstype: "proc",
|
||||
FSType: "proc",
|
||||
Source: "proc",
|
||||
VfsOpts: "rw",
|
||||
VFSOptions: "rw",
|
||||
}
|
||||
|
||||
if *infos[0] != mi {
|
||||
if infos[0] != mi {
|
||||
t.Fatalf("expected %#v, got %#v", mi, infos[0])
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,14 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r"))
|
||||
if mnttab == nil {
|
||||
return nil, fmt.Errorf("Failed to open %s", C.MNTTAB)
|
||||
}
|
||||
|
||||
var out []*Info
|
||||
var out []Info
|
||||
var mp C.struct_mnttab
|
||||
|
||||
ret := C.getmntent(mnttab, &mp)
|
||||
@ -26,12 +27,17 @@ func parseMountTable() ([]*Info, error) {
|
||||
var mountinfo Info
|
||||
mountinfo.Mountpoint = C.GoString(mp.mnt_mountp)
|
||||
mountinfo.Source = C.GoString(mp.mnt_special)
|
||||
mountinfo.Fstype = C.GoString(mp.mnt_fstype)
|
||||
mountinfo.Opts = C.GoString(mp.mnt_mntopts)
|
||||
out = append(out, &mountinfo)
|
||||
mountinfo.FSType = C.GoString(mp.mnt_fstype)
|
||||
mountinfo.Options = C.GoString(mp.mnt_mntopts)
|
||||
out = append(out, mountinfo)
|
||||
ret = C.getmntent(mnttab, &mp)
|
||||
}
|
||||
|
||||
C.fclose(mnttab)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PID collects the mounts for a specific process ID.
|
||||
func PID(pid int) ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.PID is not implemented on solaris")
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo
|
||||
// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo
|
||||
|
||||
package mountinfo
|
||||
|
||||
@ -7,6 +7,12 @@ import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
// Self retrieves a list of mounts for the current running process.
|
||||
func Self() ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.Self is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// PID collects the mounts for a specific process ID.
|
||||
func PID(pid int) ([]Info, error) {
|
||||
return nil, fmt.Errorf("mountinfo.PID is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
package mountinfo
|
||||
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
// Do NOT return an error!
|
||||
return nil, nil
|
||||
}
|
@ -36,17 +36,17 @@ type snapshotter struct {
|
||||
ms *storage.MetaStore
|
||||
}
|
||||
|
||||
func getBtrfsDevice(root string, mounts []*mountinfo.Info) (string, error) {
|
||||
func getBtrfsDevice(root string, mounts []mountinfo.Info) (string, error) {
|
||||
device := ""
|
||||
deviceMountpoint := ""
|
||||
for _, info := range mounts {
|
||||
if (info.Root == "/" || info.Root == "") && strings.HasPrefix(root, info.Mountpoint) {
|
||||
if info.Fstype == "btrfs" && len(info.Mountpoint) > len(deviceMountpoint) {
|
||||
if info.FSType == "btrfs" && len(info.Mountpoint) > len(deviceMountpoint) {
|
||||
device = info.Source
|
||||
deviceMountpoint = info.Mountpoint
|
||||
}
|
||||
if root == info.Mountpoint && info.Fstype != "btrfs" {
|
||||
return "", fmt.Errorf("%s needs to be btrfs, but seems %s", root, info.Fstype)
|
||||
if root == info.Mountpoint && info.FSType != "btrfs" {
|
||||
return "", fmt.Errorf("%s needs to be btrfs, but seems %s", root, info.FSType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,7 @@ func getBtrfsDevice(root string, mounts []*mountinfo.Info) (string, error) {
|
||||
// a file in the provided root.
|
||||
// root needs to be a mount point of btrfs.
|
||||
func NewSnapshotter(root string) (snapshot.Snapshotter, error) {
|
||||
mounts, err := mountinfo.GetMounts()
|
||||
mounts, err := mountinfo.Self()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -222,45 +222,45 @@ func TestGetBtrfsDevice(t *testing.T) {
|
||||
expectedDevice string
|
||||
expectedError string
|
||||
root string
|
||||
mounts []*mountinfo.Info
|
||||
mounts []mountinfo.Info
|
||||
}{
|
||||
{
|
||||
expectedDevice: "/dev/loop0",
|
||||
root: "/var/lib/containerd/snapshot/btrfs",
|
||||
mounts: []*mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", Fstype: "ext4", Source: "/dev/sda1"},
|
||||
{Root: "/", Mountpoint: "/var/lib/containerd/snapshot/btrfs", Fstype: "btrfs", Source: "/dev/loop0"},
|
||||
mounts: []mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", FSType: "ext4", Source: "/dev/sda1"},
|
||||
{Root: "/", Mountpoint: "/var/lib/containerd/snapshot/btrfs", FSType: "btrfs", Source: "/dev/loop0"},
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedError: "/var/lib/containerd/snapshot/btrfs is not mounted as btrfs",
|
||||
root: "/var/lib/containerd/snapshot/btrfs",
|
||||
mounts: []*mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", Fstype: "ext4", Source: "/dev/sda1"},
|
||||
mounts: []mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", FSType: "ext4", Source: "/dev/sda1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedDevice: "/dev/sda1",
|
||||
root: "/var/lib/containerd/snapshot/btrfs",
|
||||
mounts: []*mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", Fstype: "btrfs", Source: "/dev/sda1"},
|
||||
mounts: []mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", FSType: "btrfs", Source: "/dev/sda1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedDevice: "/dev/sda2",
|
||||
root: "/var/lib/containerd/snapshot/btrfs",
|
||||
mounts: []*mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", Fstype: "btrfs", Source: "/dev/sda1"},
|
||||
{Root: "/", Mountpoint: "/var/lib/containerd/snapshot/btrfs", Fstype: "btrfs", Source: "/dev/sda2"},
|
||||
mounts: []mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/", FSType: "btrfs", Source: "/dev/sda1"},
|
||||
{Root: "/", Mountpoint: "/var/lib/containerd/snapshot/btrfs", FSType: "btrfs", Source: "/dev/sda2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedDevice: "/dev/sda2",
|
||||
root: "/var/lib/containerd/snapshot/btrfs",
|
||||
mounts: []*mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/var/lib/containerd/snapshot/btrfs", Fstype: "btrfs", Source: "/dev/sda2"},
|
||||
{Root: "/", Mountpoint: "/var/lib/foooooooooooooooooooo/baaaaaaaaaaaaaaaaaaaar", Fstype: "btrfs", Source: "/dev/sda3"}, // mountpoint length longer than /var/lib/containerd/snapshot/btrfs
|
||||
{Root: "/", Mountpoint: "/", Fstype: "btrfs", Source: "/dev/sda1"},
|
||||
mounts: []mountinfo.Info{
|
||||
{Root: "/", Mountpoint: "/var/lib/containerd/snapshot/btrfs", FSType: "btrfs", Source: "/dev/sda2"},
|
||||
{Root: "/", Mountpoint: "/var/lib/foooooooooooooooooooo/baaaaaaaaaaaaaaaaaaaar", FSType: "btrfs", Source: "/dev/sda3"}, // mountpoint length longer than /var/lib/containerd/snapshot/btrfs
|
||||
{Root: "/", Mountpoint: "/", FSType: "btrfs", Source: "/dev/sda1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user