mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
vendor: moby/sys mountinfo/v0.4.0
full diff: https://github.com/moby/sys/compare/mountinfo/v0.1.3...mountinfo/v0.4.0 > Note that this dependency uses submodules, providing "github.com/moby/sys/mount" > and "github.com/moby/sys/mountinfo". Our vendoring tool (vndr) currently doesn't > support submodules, so we vendor the top-level moby/sys repository (which contains > both) and pick the most recent tag, which could be either `mountinfo/vXXX` or > `mount/vXXX`. github.com/moby/sys/mountinfo v0.4.0 -------------------------------------------------------------------------------- Breaking changes: - `PidMountInfo` is now deprecated and will be removed before v1.0; users should switch to `GetMountsFromReader` Fixes and improvements: - run filter after all fields are parsed - correct handling errors from bufio.Scan - documentation formatting fixes github.com/moby/sys/mountinfo v0.3.1 -------------------------------------------------------------------------------- - mount: use MNT_* flags from golang.org/x/sys/unix on freebsd - various godoc and CI fixes - mountinfo: make GetMountinfoFromReader Linux-specific - Add support for OpenBSD in addition to FreeBSD - mountinfo: use idiomatic naming for fields github.com/moby/sys/mountinfo v0.2.0 -------------------------------------------------------------------------------- Bug fixes: - Fix path unescaping for paths with double quotes Improvements: - Mounted: speed up by adding fast paths using openat2 (Linux-only) and stat - Mounted: relax path requirements (allow relative, non-cleaned paths, symlinks) - Unescape fstype and source fields - Documentation improvements Testing/CI: - Unit tests: exclude darwin - CI: run tests under Fedora 32 to test openat2 - TestGetMounts: fix for Ubuntu build system - Makefile: fix ignoring test failures - CI: add cross build github.com/moby/sys/mount v0.1.1 -------------------------------------------------------------------------------- https://github.com/moby/sys/releases/tag/mount%2Fv0.1.1 Improvements: - RecursiveUnmount: add a fast path (#26) - Unmount: improve doc - fix CI linter warning on Windows Testing/CI: - Unit tests: exclude darwin - Makefile: fix ignoring test failures - CI: add cross build Signed-off-by: Sebastiaan van Stijn <github@gone.nl> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
182795cff6
commit
32d506b394
25 changed files with 448 additions and 216 deletions
|
@ -159,7 +159,7 @@ func lookupZfsDataset(rootdir string) (string, error) {
|
|||
continue // may fail on fuse file systems
|
||||
}
|
||||
|
||||
if stat.Dev == wantedDev && m.Fstype == "zfs" {
|
||||
if stat.Dev == wantedDev && m.FSType == "zfs" {
|
||||
return m.Source, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,5 +69,5 @@ var (
|
|||
PrefixFilter = mountinfo.PrefixFilter
|
||||
SingleEntryFilter = mountinfo.SingleEntryFilter
|
||||
ParentsFilter = mountinfo.ParentsFilter
|
||||
FstypeFilter = mountinfo.FstypeFilter
|
||||
FstypeFilter = mountinfo.FSTypeFilter
|
||||
)
|
||||
|
|
|
@ -9,6 +9,13 @@ github.com/Microsoft/opengcs a10967154e143a36014584a6f664
|
|||
github.com/moby/locker 281af2d563954745bea9d1487c965f24d30742fe # v1.0.1
|
||||
github.com/moby/term 7f0af18e79f2784809e9cef63d0df5aa2c79d76e
|
||||
|
||||
# Note that this dependency uses submodules, providing the github.com/moby/sys/mount
|
||||
# and github.com/moby/sys/mountinfo modules. Our vendoring tool (vndr) currently
|
||||
# does not support submodules / vendoring sub-paths, so we vendor the top-level
|
||||
# moby/sys repository (which contains both) and pick the most recent tag, which
|
||||
# could be either `mountinfo/vX.Y.Z` or `mount/vX.Y.Z`.
|
||||
github.com/moby/sys 9a75fe61baf4b9788826b48b0518abecffb79b16 # mountinfo v0.4.0
|
||||
|
||||
github.com/creack/pty 3a6a957789163cacdfe0e291617a1c8e80612c11 # v1.1.9
|
||||
github.com/sirupsen/logrus 6699a89a232f3db797f2e280639854bbc4b89725 # v1.7.0
|
||||
github.com/tchap/go-patricia a7f0089c6f496e8e70402f61733606daa326cac5 # v2.3.0
|
||||
|
@ -16,7 +23,6 @@ golang.org/x/net ab34263943818b32f575efc978a3
|
|||
golang.org/x/sys aee5d888a86055dc6ab0342f9cdc7b53aaeaec62
|
||||
github.com/docker/go-units 519db1ee28dcc9fd2474ae59fca29a810482bfb1 # v0.4.0
|
||||
github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
|
||||
github.com/moby/sys 6154f11e6840c0d6b0dbb23f4125a6134b3013c9 # mountinfo/v0.1.3
|
||||
golang.org/x/text 23ae387dee1f90d29a23c0e87ee0b46038fbed0e # v0.3.3
|
||||
gotest.tools/v3 bb0d8a963040ea5048dcef1a14d8f8b58a33d4b3 # v3.0.2
|
||||
github.com/google/go-cmp 3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
|
||||
|
|
4
vendor/github.com/moby/sys/mount/doc.go
generated
vendored
Normal file
4
vendor/github.com/moby/sys/mount/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
// Package mount provides a set of functions to mount and unmount mounts.
|
||||
//
|
||||
// Currently it supports Linux. For historical reasons, there is also some support for FreeBSD.
|
||||
package mount
|
|
@ -1,28 +1,25 @@
|
|||
// +build freebsd,cgo
|
||||
// +build freebsd openbsd
|
||||
|
||||
package mount
|
||||
|
||||
/*
|
||||
#include <sys/mount.h>
|
||||
*/
|
||||
import "C"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const (
|
||||
// RDONLY will mount the filesystem as read-only.
|
||||
RDONLY = C.MNT_RDONLY
|
||||
RDONLY = unix.MNT_RDONLY
|
||||
|
||||
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
|
||||
// take effect.
|
||||
NOSUID = C.MNT_NOSUID
|
||||
NOSUID = unix.MNT_NOSUID
|
||||
|
||||
// NOEXEC will not allow execution of any binaries on the mounted file system.
|
||||
NOEXEC = C.MNT_NOEXEC
|
||||
NOEXEC = unix.MNT_NOEXEC
|
||||
|
||||
// SYNCHRONOUS will allow any I/O to the file system to be done synchronously.
|
||||
SYNCHRONOUS = C.MNT_SYNCHRONOUS
|
||||
SYNCHRONOUS = unix.MNT_SYNCHRONOUS
|
||||
|
||||
// NOATIME will not update the file access time when reading from a file.
|
||||
NOATIME = C.MNT_NOATIME
|
||||
NOATIME = unix.MNT_NOATIME
|
||||
)
|
||||
|
||||
// These flags are unsupported.
|
|
@ -1,3 +1,5 @@
|
|||
// +build !darwin,!windows
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
30
vendor/github.com/moby/sys/mount/flags_unsupported.go
generated
vendored
30
vendor/github.com/moby/sys/mount/flags_unsupported.go
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
// +build !linux,!freebsd freebsd,!cgo
|
||||
|
||||
package mount
|
||||
|
||||
// These flags are unsupported.
|
||||
const (
|
||||
BIND = 0
|
||||
DIRSYNC = 0
|
||||
MANDLOCK = 0
|
||||
NOATIME = 0
|
||||
NODEV = 0
|
||||
NODIRATIME = 0
|
||||
NOEXEC = 0
|
||||
NOSUID = 0
|
||||
UNBINDABLE = 0
|
||||
RUNBINDABLE = 0
|
||||
PRIVATE = 0
|
||||
RPRIVATE = 0
|
||||
SHARED = 0
|
||||
RSHARED = 0
|
||||
SLAVE = 0
|
||||
RSLAVE = 0
|
||||
RBIND = 0
|
||||
RELATIME = 0
|
||||
REMOUNT = 0
|
||||
STRICTATIME = 0
|
||||
SYNCHRONOUS = 0
|
||||
RDONLY = 0
|
||||
mntDetach = 0
|
||||
)
|
4
vendor/github.com/moby/sys/mount/go.mod
generated
vendored
4
vendor/github.com/moby/sys/mount/go.mod
generated
vendored
|
@ -3,6 +3,6 @@ module github.com/moby/sys/mount
|
|||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/moby/sys/mountinfo v0.1.0
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
|
||||
github.com/moby/sys/mountinfo v0.3.1
|
||||
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860
|
||||
)
|
||||
|
|
56
vendor/github.com/moby/sys/mount/mount.go
generated
vendored
56
vendor/github.com/moby/sys/mount/mount.go
generated
vendored
|
@ -1,56 +0,0 @@
|
|||
// +build go1.13
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/moby/sys/mountinfo"
|
||||
)
|
||||
|
||||
// Mount will mount filesystem according to the specified configuration.
|
||||
// Options must be specified like the mount or fstab unix commands:
|
||||
// "opt1=val1,opt2=val2". See flags.go for supported option flags.
|
||||
func Mount(device, target, mType, options string) error {
|
||||
flag, data := parseOptions(options)
|
||||
return mount(device, target, mType, uintptr(flag), data)
|
||||
}
|
||||
|
||||
// Unmount lazily unmounts a filesystem on supported platforms, otherwise
|
||||
// does a normal unmount.
|
||||
func Unmount(target string) error {
|
||||
return unmount(target, mntDetach)
|
||||
}
|
||||
|
||||
// RecursiveUnmount unmounts the target and all mounts underneath, starting with
|
||||
// the deepsest mount first.
|
||||
func RecursiveUnmount(target string) error {
|
||||
mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make the deepest mount be first
|
||||
sort.Slice(mounts, func(i, j int) bool {
|
||||
return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
|
||||
})
|
||||
|
||||
var suberr error
|
||||
for i, m := range mounts {
|
||||
err = unmount(m.Mountpoint, mntDetach)
|
||||
if err != nil {
|
||||
if i == len(mounts)-1 { // last mount
|
||||
return fmt.Errorf("%w (possible cause: %s)", err, suberr)
|
||||
}
|
||||
// This is a submount, we can ignore the error for now,
|
||||
// the final unmount will fail if this is a real problem.
|
||||
// With that in mind, the _first_ failed unmount error
|
||||
// might be the real error cause, so let's keep it.
|
||||
if suberr == nil {
|
||||
suberr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
87
vendor/github.com/moby/sys/mount/mount_unix.go
generated
vendored
Normal file
87
vendor/github.com/moby/sys/mount/mount_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
// +build !darwin,!windows
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/moby/sys/mountinfo"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Mount will mount filesystem according to the specified configuration.
|
||||
// Options must be specified like the mount or fstab unix commands:
|
||||
// "opt1=val1,opt2=val2". See flags.go for supported option flags.
|
||||
func Mount(device, target, mType, options string) error {
|
||||
flag, data := parseOptions(options)
|
||||
return mount(device, target, mType, uintptr(flag), data)
|
||||
}
|
||||
|
||||
// Unmount lazily unmounts a filesystem on supported platforms, otherwise does
|
||||
// a normal unmount. If target is not a mount point, no error is returned.
|
||||
func Unmount(target string) error {
|
||||
err := unix.Unmount(target, mntDetach)
|
||||
if err == nil || err == unix.EINVAL {
|
||||
// Ignore "not mounted" error here. Note the same error
|
||||
// can be returned if flags are invalid, so this code
|
||||
// assumes that the flags value is always correct.
|
||||
return nil
|
||||
}
|
||||
|
||||
return &mountError{
|
||||
op: "umount",
|
||||
target: target,
|
||||
flags: uintptr(mntDetach),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// RecursiveUnmount unmounts the target and all mounts underneath, starting
|
||||
// with the deepest mount first. The argument does not have to be a mount
|
||||
// point itself.
|
||||
func RecursiveUnmount(target string) error {
|
||||
// Fast path, works if target is a mount point that can be unmounted.
|
||||
// On Linux, mntDetach flag ensures a recursive unmount. For other
|
||||
// platforms, if there are submounts, we'll get EBUSY (and fall back
|
||||
// to the slow path). NOTE we do not ignore EINVAL here as target might
|
||||
// not be a mount point itself (but there can be mounts underneath).
|
||||
if err := unix.Unmount(target, mntDetach); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Slow path: get all submounts, sort, unmount one by one.
|
||||
mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make the deepest mount be first
|
||||
sort.Slice(mounts, func(i, j int) bool {
|
||||
return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
|
||||
})
|
||||
|
||||
var (
|
||||
suberr error
|
||||
lastMount = len(mounts) - 1
|
||||
)
|
||||
for i, m := range mounts {
|
||||
err = Unmount(m.Mountpoint)
|
||||
if err != nil {
|
||||
if i == lastMount {
|
||||
if suberr != nil {
|
||||
return fmt.Errorf("%w (possible cause: %s)", err, suberr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// This is a submount, we can ignore the error for now,
|
||||
// the final unmount will fail if this is a real problem.
|
||||
// With that in mind, the _first_ failed unmount error
|
||||
// might be the real error cause, so let's keep it.
|
||||
if suberr == nil {
|
||||
suberr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// +build freebsd,cgo openbsd,cgo
|
||||
|
||||
package mount
|
||||
|
||||
/*
|
4
vendor/github.com/moby/sys/mount/mounter_unsupported.go
generated
vendored
4
vendor/github.com/moby/sys/mount/mounter_unsupported.go
generated
vendored
|
@ -1,7 +1,7 @@
|
|||
// +build !linux,!freebsd freebsd,!cgo
|
||||
// +build !linux,!freebsd,!openbsd,!windows freebsd,!cgo openbsd,!cgo
|
||||
|
||||
package mount
|
||||
|
||||
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||
panic("Not implemented")
|
||||
panic("cgo required on freebsd and openbsd")
|
||||
}
|
||||
|
|
22
vendor/github.com/moby/sys/mount/unmount_unix.go
generated
vendored
22
vendor/github.com/moby/sys/mount/unmount_unix.go
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package mount
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func unmount(target string, flags int) error {
|
||||
err := unix.Unmount(target, flags)
|
||||
if err == nil || err == unix.EINVAL {
|
||||
// Ignore "not mounted" error here. Note the same error
|
||||
// can be returned if flags are invalid, so this code
|
||||
// assumes that the flags value is always correct.
|
||||
return nil
|
||||
}
|
||||
|
||||
return &mountError{
|
||||
op: "umount",
|
||||
target: target,
|
||||
flags: uintptr(flags),
|
||||
err: err,
|
||||
}
|
||||
}
|
7
vendor/github.com/moby/sys/mount/unmount_unsupported.go
generated
vendored
7
vendor/github.com/moby/sys/mount/unmount_unsupported.go
generated
vendored
|
@ -1,7 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
package mount
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
panic("Not implemented")
|
||||
}
|
44
vendor/github.com/moby/sys/mountinfo/doc.go
generated
vendored
Normal file
44
vendor/github.com/moby/sys/mountinfo/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Package mountinfo provides a set of functions to retrieve information about OS mounts.
|
||||
//
|
||||
// Currently it supports Linux. For historical reasons, there is also some support for FreeBSD and OpenBSD,
|
||||
// and a shallow implementation for Windows, but in general this is Linux-only package, so
|
||||
// the rest of the document only applies to Linux, unless explicitly specified otherwise.
|
||||
//
|
||||
// In Linux, information about mounts seen by the current process is available from
|
||||
// /proc/self/mountinfo. Note that due to mount namespaces, different processes can
|
||||
// see different mounts. A per-process mountinfo table is available from /proc/<PID>/mountinfo,
|
||||
// where <PID> is a numerical process identifier.
|
||||
//
|
||||
// In general, /proc is not a very efficient interface, and mountinfo is not an exception.
|
||||
// For example, there is no way to get information about a specific mount point (i.e. it
|
||||
// is all-or-nothing). This package tries to hide the /proc ineffectiveness by using
|
||||
// parse filters while reading mountinfo. A filter can skip some entries, or stop
|
||||
// processing the rest of the file once the needed information is found.
|
||||
//
|
||||
// For mountinfo filters that accept path as an argument, the path must be absolute,
|
||||
// having all symlinks resolved, and being cleaned (i.e. no extra slashes or dots).
|
||||
// One way to achieve all of the above is to employ filepath.Abs followed by
|
||||
// filepath.EvalSymlinks (the latter calls filepath.Clean on the result so
|
||||
// there is no need to explicitly call filepath.Clean).
|
||||
//
|
||||
// NOTE that in many cases there is no need to consult mountinfo at all. Here are some
|
||||
// of the cases where mountinfo should not be parsed:
|
||||
//
|
||||
// 1. Before performing a mount. Usually, this is not needed, but if required (say to
|
||||
// prevent over-mounts), to check whether a directory is mounted, call os.Lstat
|
||||
// on it and its parent directory, and compare their st.Sys().(*syscall.Stat_t).Dev
|
||||
// fields -- if they differ, then the directory is the mount point. NOTE this does
|
||||
// not work for bind mounts. Optionally, the filesystem type can also be checked
|
||||
// by calling unix.Statfs and checking the Type field (i.e. filesystem type).
|
||||
//
|
||||
// 2. After performing a mount. If there is no error returned, the mount succeeded;
|
||||
// checking the mount table for a new mount is redundant and expensive.
|
||||
//
|
||||
// 3. Before performing an unmount. It is more efficient to do an unmount and ignore
|
||||
// a specific error (EINVAL) which tells the directory is not mounted.
|
||||
//
|
||||
// 4. After performing an unmount. If there is no error returned, the unmount succeeded.
|
||||
//
|
||||
// 5. To find the mount point root of a specific directory. You can perform os.Stat()
|
||||
// on the directory and traverse up until the Dev field of a parent directory differs.
|
||||
package mountinfo
|
2
vendor/github.com/moby/sys/mountinfo/go.mod
generated
vendored
2
vendor/github.com/moby/sys/mountinfo/go.mod
generated
vendored
|
@ -1,3 +1,5 @@
|
|||
module github.com/moby/sys/mountinfo
|
||||
|
||||
go 1.14
|
||||
|
||||
require golang.org/x/sys v0.0.0-20200909081042-eff7692f9009
|
||||
|
|
58
vendor/github.com/moby/sys/mountinfo/mounted_linux.go
generated
vendored
Normal file
58
vendor/github.com/moby/sys/mountinfo/mounted_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
package mountinfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// mountedByOpenat2 is a method of detecting a mount that works for all kinds
|
||||
// of mounts (incl. bind mounts), but requires a recent (v5.6+) linux kernel.
|
||||
func mountedByOpenat2(path string) (bool, error) {
|
||||
dir, last := filepath.Split(path)
|
||||
|
||||
dirfd, err := unix.Openat2(unix.AT_FDCWD, dir, &unix.OpenHow{
|
||||
Flags: unix.O_PATH | unix.O_CLOEXEC,
|
||||
})
|
||||
if err != nil {
|
||||
if err == unix.ENOENT { // not a mount
|
||||
return false, nil
|
||||
}
|
||||
return false, &os.PathError{Op: "openat2", Path: dir, Err: err}
|
||||
}
|
||||
fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{
|
||||
Flags: unix.O_PATH | unix.O_CLOEXEC | unix.O_NOFOLLOW,
|
||||
Resolve: unix.RESOLVE_NO_XDEV,
|
||||
})
|
||||
_ = unix.Close(dirfd)
|
||||
switch err {
|
||||
case nil: // definitely not a mount
|
||||
_ = unix.Close(fd)
|
||||
return false, nil
|
||||
case unix.EXDEV: // definitely a mount
|
||||
return true, nil
|
||||
case unix.ENOENT: // not a mount
|
||||
return false, nil
|
||||
}
|
||||
// not sure
|
||||
return false, &os.PathError{Op: "openat2", Path: path, Err: err}
|
||||
}
|
||||
|
||||
func mounted(path string) (bool, error) {
|
||||
// Try a fast path, using openat2() with RESOLVE_NO_XDEV.
|
||||
mounted, err := mountedByOpenat2(path)
|
||||
if err == nil {
|
||||
return mounted, nil
|
||||
}
|
||||
// Another fast path: compare st.st_dev fields.
|
||||
mounted, err = mountedByStat(path)
|
||||
// This does not work for bind mounts, so false negative
|
||||
// is possible, therefore only trust if return is true.
|
||||
if mounted && err == nil {
|
||||
return mounted, nil
|
||||
}
|
||||
|
||||
// Fallback to parsing mountinfo
|
||||
return mountedByMountinfo(path)
|
||||
}
|
66
vendor/github.com/moby/sys/mountinfo/mounted_unix.go
generated
vendored
Normal file
66
vendor/github.com/moby/sys/mountinfo/mounted_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
// +build linux freebsd,cgo openbsd,cgo
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func mountedByStat(path string) (bool, error) {
|
||||
var st unix.Stat_t
|
||||
|
||||
if err := unix.Lstat(path, &st); err != nil {
|
||||
if err == unix.ENOENT {
|
||||
// Treat ENOENT as "not mounted".
|
||||
return false, nil
|
||||
}
|
||||
return false, &os.PathError{Op: "stat", Path: path, Err: err}
|
||||
}
|
||||
dev := st.Dev
|
||||
parent := filepath.Dir(path)
|
||||
if err := unix.Lstat(parent, &st); err != nil {
|
||||
return false, &os.PathError{Op: "stat", Path: parent, Err: err}
|
||||
}
|
||||
if dev != st.Dev {
|
||||
// Device differs from that of parent,
|
||||
// so definitely a mount point.
|
||||
return true, nil
|
||||
}
|
||||
// NB: this does not detect bind mounts on Linux.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func normalizePath(path string) (realPath string, err error) {
|
||||
if realPath, err = filepath.Abs(path); err != nil {
|
||||
return "", fmt.Errorf("unable to get absolute path for %q: %w", path, err)
|
||||
}
|
||||
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
||||
return "", fmt.Errorf("failed to canonicalise path for %q: %w", path, err)
|
||||
}
|
||||
if _, err := os.Stat(realPath); err != nil {
|
||||
return "", fmt.Errorf("failed to stat target of %q: %w", path, err)
|
||||
}
|
||||
return realPath, nil
|
||||
}
|
||||
|
||||
func mountedByMountinfo(path string) (bool, error) {
|
||||
path, err := normalizePath(path)
|
||||
if err != nil {
|
||||
if errors.Is(err, unix.ENOENT) {
|
||||
// treat ENOENT as "not mounted"
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
entries, err := GetMounts(SingleEntryFilter(path))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return len(entries) > 0, nil
|
||||
}
|
42
vendor/github.com/moby/sys/mountinfo/mountinfo.go
generated
vendored
42
vendor/github.com/moby/sys/mountinfo/mountinfo.go
generated
vendored
|
@ -1,6 +1,8 @@
|
|||
package mountinfo
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetMounts retrieves a list of mounts for the current running process,
|
||||
// with an optional filter applied (use nil for no filter).
|
||||
|
@ -8,23 +10,17 @@ func GetMounts(f FilterFunc) ([]*Info, error) {
|
|||
return parseMountTable(f)
|
||||
}
|
||||
|
||||
// GetMountsFromReader retrieves a list of mounts from the
|
||||
// reader provided, with an optional filter applied (use nil
|
||||
// for no filter). This can be useful in tests or benchmarks
|
||||
// that provide a fake mountinfo data.
|
||||
func GetMountsFromReader(reader io.Reader, f FilterFunc) ([]*Info, error) {
|
||||
return parseInfoFile(reader, f)
|
||||
}
|
||||
|
||||
// Mounted determines if a specified mountpoint has been mounted.
|
||||
// On Linux it looks at /proc/self/mountinfo.
|
||||
func Mounted(mountpoint string) (bool, error) {
|
||||
entries, err := GetMounts(SingleEntryFilter(mountpoint))
|
||||
if err != nil {
|
||||
return false, err
|
||||
// Mounted determines if a specified path is a mount point.
|
||||
//
|
||||
// The argument must be an absolute path, with all symlinks resolved, and clean.
|
||||
// One way to ensure it is to process the path using filepath.Abs followed by
|
||||
// filepath.EvalSymlinks before calling this function.
|
||||
func Mounted(path string) (bool, error) {
|
||||
// root is always mounted
|
||||
if path == string(os.PathSeparator) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return len(entries) > 0, nil
|
||||
return mounted(path)
|
||||
}
|
||||
|
||||
// Info reveals information about a particular mounted filesystem. This
|
||||
|
@ -50,18 +46,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
|
||||
// VFSOptions represents per super block options.
|
||||
VFSOptions string
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build freebsd,cgo openbsd,cgo
|
||||
|
||||
package mountinfo
|
||||
|
||||
/*
|
||||
|
@ -33,7 +35,7 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|||
var mountinfo Info
|
||||
var skip, stop bool
|
||||
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
|
||||
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
|
||||
mountinfo.FSType = C.GoString(&entry.f_fstypename[0])
|
||||
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
||||
|
||||
if filter != nil {
|
||||
|
@ -51,3 +53,15 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func mounted(path string) (bool, error) {
|
||||
// Fast path: compare st.st_dev fields.
|
||||
// This should always work for FreeBSD and OpenBSD.
|
||||
mounted, err := mountedByStat(path)
|
||||
if err == nil {
|
||||
return mounted, nil
|
||||
}
|
||||
|
||||
// Fallback to parsing mountinfo
|
||||
return mountedByMountinfo(path)
|
||||
}
|
26
vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
generated
vendored
26
vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
generated
vendored
|
@ -6,16 +6,16 @@ import "strings"
|
|||
// used to filter out mountinfo entries we're not interested in,
|
||||
// and/or stop further processing if we found what we wanted.
|
||||
//
|
||||
// It takes a pointer to the Info struct (not fully populated,
|
||||
// currently only Mountpoint, Fstype, Source, and (on Linux)
|
||||
// VfsOpts are filled in), and returns two booleans:
|
||||
// It takes a pointer to the Info struct (fully populated with all available
|
||||
// fields on the GOOS platform), and returns two booleans:
|
||||
//
|
||||
// - skip: true if the entry should be skipped
|
||||
// - stop: true if parsing should be stopped after the entry
|
||||
// skip: true if the entry should be skipped;
|
||||
//
|
||||
// stop: true if parsing should be stopped after the entry.
|
||||
type FilterFunc func(*Info) (skip, stop bool)
|
||||
|
||||
// PrefixFilter discards all entries whose mount points
|
||||
// do not start with a specific prefix
|
||||
// do not start with a specific prefix.
|
||||
func PrefixFilter(prefix string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
skip := !strings.HasPrefix(m.Mountpoint, prefix)
|
||||
|
@ -23,7 +23,7 @@ func PrefixFilter(prefix string) FilterFunc {
|
|||
}
|
||||
}
|
||||
|
||||
// SingleEntryFilter looks for a specific entry
|
||||
// SingleEntryFilter looks for a specific entry.
|
||||
func SingleEntryFilter(mp string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
if m.Mountpoint == mp {
|
||||
|
@ -36,8 +36,8 @@ func SingleEntryFilter(mp string) FilterFunc {
|
|||
// ParentsFilter returns all entries whose mount points
|
||||
// can be parents of a path specified, discarding others.
|
||||
//
|
||||
// For example, given `/var/lib/docker/something`, entries
|
||||
// like `/var/lib/docker`, `/var` and `/` are returned.
|
||||
// For example, given /var/lib/docker/something, entries
|
||||
// like /var/lib/docker, /var and / are returned.
|
||||
func ParentsFilter(path string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
skip := !strings.HasPrefix(path, m.Mountpoint)
|
||||
|
@ -45,12 +45,12 @@ func ParentsFilter(path string) FilterFunc {
|
|||
}
|
||||
}
|
||||
|
||||
// FstypeFilter returns all entries that match provided fstype(s).
|
||||
func FstypeFilter(fstype ...string) FilterFunc {
|
||||
// FSTypeFilter returns all entries that match provided fstype(s).
|
||||
func FSTypeFilter(fstype ...string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
for _, t := range fstype {
|
||||
if m.Fstype == t {
|
||||
return false, false // don't skeep, keep going
|
||||
if m.FSType == t {
|
||||
return false, false // don't skip, keep going
|
||||
}
|
||||
}
|
||||
return true, false // skip, keep going
|
||||
|
|
132
vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
generated
vendored
132
vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
generated
vendored
|
@ -1,5 +1,3 @@
|
|||
// +build go1.13
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
|
@ -11,14 +9,18 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||
// GetMountsFromReader retrieves a list of mounts from the
|
||||
// reader provided, with an optional filter applied (use nil
|
||||
// for no filter). This can be useful in tests or benchmarks
|
||||
// that provide a fake mountinfo data.
|
||||
//
|
||||
// This function is Linux-specific.
|
||||
func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
out := []*Info{}
|
||||
var err error
|
||||
for s.Scan() {
|
||||
if err = s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error
|
||||
|
||||
/*
|
||||
See http://man7.org/linux/man-pages/man5/proc.5.html
|
||||
|
||||
|
@ -70,26 +72,19 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
|||
|
||||
p := &Info{}
|
||||
|
||||
// Fill in the fields that a filter might check
|
||||
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
|
||||
p.Mountpoint, err = unescape(fields[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote mount point field: %w", fields[4], err)
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: mount point: %w", fields[4], err)
|
||||
}
|
||||
p.Fstype = fields[sepIdx+1]
|
||||
p.Source = fields[sepIdx+2]
|
||||
p.VfsOpts = fields[sepIdx+3]
|
||||
|
||||
// Run a filter soon so we can skip parsing/adding entries
|
||||
// the caller is not interested in
|
||||
var skip, stop bool
|
||||
if filter != nil {
|
||||
skip, stop = filter(p)
|
||||
if skip {
|
||||
continue
|
||||
p.FSType, err = unescape(fields[sepIdx+1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: fstype: %w", fields[sepIdx+1], err)
|
||||
}
|
||||
p.Source, err = unescape(fields[sepIdx+2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: source: %w", fields[sepIdx+2], err)
|
||||
}
|
||||
|
||||
// Fill in the rest of the fields
|
||||
p.VFSOptions = fields[sepIdx+3]
|
||||
|
||||
// ignore any numbers parsing errors, as there should not be any
|
||||
p.ID, _ = strconv.Atoi(fields[0])
|
||||
|
@ -101,12 +96,12 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
|||
p.Major, _ = strconv.Atoi(mm[0])
|
||||
p.Minor, _ = strconv.Atoi(mm[1])
|
||||
|
||||
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
|
||||
p.Root, err = unescape(fields[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote root field: %w", fields[3], err)
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: root: %w", fields[3], err)
|
||||
}
|
||||
|
||||
p.Opts = fields[5]
|
||||
p.Options = fields[5]
|
||||
|
||||
// zero or more optional fields
|
||||
switch {
|
||||
|
@ -118,11 +113,23 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
|||
p.Optional = strings.Join(fields[6:sepIdx-1], " ")
|
||||
}
|
||||
|
||||
// Run the filter after parsing all of the fields.
|
||||
var skip, stop bool
|
||||
if filter != nil {
|
||||
skip, stop = filter(p)
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, p)
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
|
@ -135,12 +142,17 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f, filter)
|
||||
return GetMountsFromReader(f, filter)
|
||||
}
|
||||
|
||||
// PidMountInfo collects the mounts for a specific process ID. If the process
|
||||
// ID is unknown, it is better to use `GetMounts` which will inspect
|
||||
// "/proc/self/mountinfo" instead.
|
||||
// PidMountInfo retrieves the list of mounts from a given process' mount
|
||||
// namespace. Unless there is a need to get mounts from a mount namespace
|
||||
// different from that of a calling process, use GetMounts.
|
||||
//
|
||||
// This function is Linux-specific.
|
||||
//
|
||||
// Deprecated: this will be removed before v1; use GetMountsFromReader with
|
||||
// opened /proc/<pid>/mountinfo as an argument instead.
|
||||
func PidMountInfo(pid int) ([]*Info, error) {
|
||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
|
@ -148,5 +160,63 @@ func PidMountInfo(pid int) ([]*Info, error) {
|
|||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f, nil)
|
||||
return GetMountsFromReader(f, nil)
|
||||
}
|
||||
|
||||
// A few specific characters in mountinfo path entries (root and mountpoint)
|
||||
// are escaped using a backslash followed by a character's ascii code in octal.
|
||||
//
|
||||
// space -- as \040
|
||||
// tab (aka \t) -- as \011
|
||||
// newline (aka \n) -- as \012
|
||||
// backslash (aka \\) -- as \134
|
||||
//
|
||||
// This function converts path from mountinfo back, i.e. it unescapes the above sequences.
|
||||
func unescape(path string) (string, error) {
|
||||
// try to avoid copying
|
||||
if strings.IndexByte(path, '\\') == -1 {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// The following code is UTF-8 transparent as it only looks for some
|
||||
// specific characters (backslash and 0..7) with values < utf8.RuneSelf,
|
||||
// and everything else is passed through as is.
|
||||
buf := make([]byte, len(path))
|
||||
bufLen := 0
|
||||
for i := 0; i < len(path); i++ {
|
||||
if path[i] != '\\' {
|
||||
buf[bufLen] = path[i]
|
||||
bufLen++
|
||||
continue
|
||||
}
|
||||
s := path[i:]
|
||||
if len(s) < 4 {
|
||||
// too short
|
||||
return "", fmt.Errorf("bad escape sequence %q: too short", s)
|
||||
}
|
||||
c := s[1]
|
||||
switch c {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
v := c - '0'
|
||||
for j := 2; j < 4; j++ { // one digit already; two more
|
||||
if s[j] < '0' || s[j] > '7' {
|
||||
return "", fmt.Errorf("bad escape sequence %q: not a digit", s[:3])
|
||||
}
|
||||
x := s[j] - '0'
|
||||
v = (v << 3) | x
|
||||
}
|
||||
if v > 255 {
|
||||
return "", fmt.Errorf("bad escape sequence %q: out of range" + s[:3])
|
||||
}
|
||||
buf[bufLen] = v
|
||||
bufLen++
|
||||
i += 3
|
||||
continue
|
||||
default:
|
||||
return "", fmt.Errorf("bad escape sequence %q: not a digit" + s[:3])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf[:bufLen]), nil
|
||||
}
|
||||
|
|
11
vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
generated
vendored
11
vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
generated
vendored
|
@ -1,17 +1,18 @@
|
|||
// +build !windows,!linux,!freebsd freebsd,!cgo
|
||||
// +build !windows,!linux,!freebsd,!openbsd freebsd,!cgo openbsd,!cgo
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var errNotImplemented = fmt.Errorf("not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
func parseMountTable(_ FilterFunc) ([]*Info, error) {
|
||||
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
|
||||
return parseMountTable(f)
|
||||
func mounted(path string) (bool, error) {
|
||||
return false, errNotImplemented
|
||||
}
|
||||
|
|
6
vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
generated
vendored
6
vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
generated
vendored
|
@ -1,12 +1,10 @@
|
|||
package mountinfo
|
||||
|
||||
import "io"
|
||||
|
||||
func parseMountTable(_ FilterFunc) ([]*Info, error) {
|
||||
// Do NOT return an error!
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
|
||||
return parseMountTable(f)
|
||||
func mounted(_ string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -221,17 +221,17 @@ func TestCreateWithOpts(t *testing.T) {
|
|||
|
||||
info := mountInfos[0]
|
||||
t.Logf("%+v", info)
|
||||
if info.Fstype != "tmpfs" {
|
||||
t.Fatalf("expected tmpfs mount, got %q", info.Fstype)
|
||||
if info.FSType != "tmpfs" {
|
||||
t.Fatalf("expected tmpfs mount, got %q", info.FSType)
|
||||
}
|
||||
if info.Source != "tmpfs" {
|
||||
t.Fatalf("expected tmpfs mount, got %q", info.Source)
|
||||
}
|
||||
if !strings.Contains(info.VfsOpts, "uid=1000") {
|
||||
t.Fatalf("expected mount info to have uid=1000: %q", info.VfsOpts)
|
||||
if !strings.Contains(info.VFSOptions, "uid=1000") {
|
||||
t.Fatalf("expected mount info to have uid=1000: %q", info.VFSOptions)
|
||||
}
|
||||
if !strings.Contains(info.VfsOpts, "size=1024k") {
|
||||
t.Fatalf("expected mount info to have size=1024k: %q", info.VfsOpts)
|
||||
if !strings.Contains(info.VFSOptions, "size=1024k") {
|
||||
t.Fatalf("expected mount info to have size=1024k: %q", info.VFSOptions)
|
||||
}
|
||||
|
||||
if v.active.count != 1 {
|
||||
|
|
Loading…
Reference in a new issue