github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/pkg/mount/mount.go (about)

     1  package mount
     2  
     3  import (
     4  	"sort"
     5  	"strings"
     6  
     7  	"github.com/sirupsen/logrus"
     8  )
     9  
    10  // GetMounts retrieves a list of mounts for the current running process.
    11  func GetMounts() ([]*Info, error) {
    12  	return parseMountTable()
    13  }
    14  
    15  // Mounted determines if a specified mountpoint has been mounted.
    16  // On Linux it looks at /proc/self/mountinfo.
    17  func Mounted(mountpoint string) (bool, error) {
    18  	entries, err := parseMountTable()
    19  	if err != nil {
    20  		return false, err
    21  	}
    22  
    23  	// Search the table for the mountpoint
    24  	for _, e := range entries {
    25  		if e.Mountpoint == mountpoint {
    26  			return true, nil
    27  		}
    28  	}
    29  	return false, nil
    30  }
    31  
    32  // Mount will mount filesystem according to the specified configuration, on the
    33  // condition that the target path is *not* already mounted. Options must be
    34  // specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
    35  // flags.go for supported option flags.
    36  func Mount(device, target, mType, options string) error {
    37  	flag, _ := parseOptions(options)
    38  	if flag&REMOUNT != REMOUNT {
    39  		if mounted, err := Mounted(target); err != nil || mounted {
    40  			return err
    41  		}
    42  	}
    43  	return ForceMount(device, target, mType, options)
    44  }
    45  
    46  // ForceMount will mount a filesystem according to the specified configuration,
    47  // *regardless* if the target path is not already mounted. Options must be
    48  // specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
    49  // flags.go for supported option flags.
    50  func ForceMount(device, target, mType, options string) error {
    51  	flag, data := parseOptions(options)
    52  	return mount(device, target, mType, uintptr(flag), data)
    53  }
    54  
    55  // Unmount lazily unmounts a filesystem on supported platforms, otherwise
    56  // does a normal unmount.
    57  func Unmount(target string) error {
    58  	if mounted, err := Mounted(target); err != nil || !mounted {
    59  		return err
    60  	}
    61  	return unmount(target, mntDetach)
    62  }
    63  
    64  // RecursiveUnmount unmounts the target and all mounts underneath, starting with
    65  // the deepsest mount first.
    66  func RecursiveUnmount(target string) error {
    67  	mounts, err := GetMounts()
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	// Make the deepest mount be first
    73  	sort.Sort(sort.Reverse(byMountpoint(mounts)))
    74  
    75  	for i, m := range mounts {
    76  		if !strings.HasPrefix(m.Mountpoint, target) {
    77  			continue
    78  		}
    79  		logrus.Debugf("Trying to unmount %s", m.Mountpoint)
    80  		err = Unmount(m.Mountpoint)
    81  		if err != nil && i == len(mounts)-1 {
    82  			if mounted, err := Mounted(m.Mountpoint); err != nil || mounted {
    83  				return err
    84  			}
    85  			// Ignore errors for submounts and continue trying to unmount others
    86  			// The final unmount should fail if there ane any submounts remaining
    87  		} else if err != nil {
    88  			logrus.Errorf("Failed to unmount %s: %v", m.Mountpoint, err)
    89  		} else if err == nil {
    90  			logrus.Debugf("Unmounted %s", m.Mountpoint)
    91  		}
    92  	}
    93  	return nil
    94  }