github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/mount/mount_linux.go (about)

     1  // Copyright 2012-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package mount implements mounting, moving, and unmounting file systems.
     6  package mount
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"os"
    12  
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  // Most commonly used mount flags.
    17  const (
    18  	MS_RDONLY   = unix.MS_RDONLY
    19  	MS_BIND     = unix.MS_BIND
    20  	MS_LAZYTIME = unix.MS_LAZYTIME
    21  	MS_NOEXEC   = unix.MS_NOEXEC
    22  	MS_NOSUID   = unix.MS_NOSUID
    23  	MS_NOUSER   = unix.MS_NOUSER
    24  	MS_RELATIME = unix.MS_RELATIME
    25  	MS_SYNC     = unix.MS_SYNC
    26  	MS_NOATIME  = unix.MS_NOATIME
    27  
    28  	ReadOnly = unix.MS_RDONLY | unix.MS_NOATIME
    29  )
    30  
    31  // Unmount flags.
    32  const (
    33  	MNT_FORCE  = unix.MNT_FORCE
    34  	MNT_DETACH = unix.MNT_DETACH
    35  )
    36  
    37  // Mounter is a device that can be attached at a file system path.
    38  type Mounter interface {
    39  	// Mount attaches the device at path.
    40  	Mount(path string, flags uintptr) (*MountPoint, error)
    41  }
    42  
    43  // MountPoint represents a mounted file system.
    44  type MountPoint struct {
    45  	Path   string
    46  	Device string
    47  	FSType string
    48  	Flags  uintptr
    49  	Data   string
    50  }
    51  
    52  // String implements fmt.Stringer.
    53  func (mp *MountPoint) String() string {
    54  	return fmt.Sprintf("MountPoint(path=%s, device=%s, fs=%s, flags=%#x, data=%s)", mp.Path, mp.Device, mp.FSType, mp.Flags, mp.Data)
    55  }
    56  
    57  // Unmount unmounts a file system that was previously mounted.
    58  func (mp *MountPoint) Unmount(flags uintptr) error {
    59  	if err := unix.Unmount(mp.Path, int(flags)); err != nil {
    60  		return &os.PathError{
    61  			Op:   "unmount",
    62  			Path: mp.Path,
    63  			Err:  fmt.Errorf("flags %#x: %v", flags, err),
    64  		}
    65  	}
    66  	return nil
    67  }
    68  
    69  // Mount attaches the fsType file system at path.
    70  //
    71  // dev is the device to mount (this is often the path of a block device, name
    72  // of a file, or a placeholder string). data usually contains arguments for the
    73  // specific file system.
    74  func Mount(dev, path, fsType, data string, flags uintptr) (*MountPoint, error) {
    75  	// Create the mount point if it doesn't already exist.
    76  	if err := os.MkdirAll(path, 0666); err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	if err := unix.Mount(dev, path, fsType, flags, data); err != nil {
    81  		return nil, &os.PathError{
    82  			Op:   "mount",
    83  			Path: path,
    84  			Err:  fmt.Errorf("from device %q (fs type %s, flags %#x): %v", dev, fsType, flags, err),
    85  		}
    86  	}
    87  	return &MountPoint{
    88  		Path:   path,
    89  		Device: dev,
    90  		FSType: fsType,
    91  		Data:   data,
    92  		Flags:  flags,
    93  	}, nil
    94  }
    95  
    96  // TryMount tries to mount a device on the given mountpoint, trying in order
    97  // the supported block device file systems on the system.
    98  func TryMount(device, path, data string, flags uintptr) (*MountPoint, error) {
    99  	// TryMount only works on existing block devices. No weirdo devices
   100  	// like 9P.
   101  	if _, err := os.Stat(device); err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	fs, err := GetBlockFilesystems()
   106  	if err != nil {
   107  		return nil, fmt.Errorf("failed to mount %s on %s: %v", device, path, err)
   108  	}
   109  	for _, fstype := range fs {
   110  		mp, err := Mount(device, path, fstype, data, flags)
   111  		if err != nil {
   112  			continue
   113  		}
   114  		return mp, nil
   115  	}
   116  	return nil, fmt.Errorf("no suitable filesystem (out of %v) found to mount %s at %v", fs, device, path)
   117  }
   118  
   119  // Unmount detaches any file system mounted at path.
   120  //
   121  // force forces an unmount regardless of currently open or otherwise used files
   122  // within the file system to be unmounted.
   123  //
   124  // lazy disallows future uses of any files below path -- i.e. it hides the file
   125  // system mounted at path, but the file system itself is still active and any
   126  // currently open files can continue to be used. When all references to files
   127  // from this file system are gone, the file system will actually be unmounted.
   128  func Unmount(path string, force, lazy bool) error {
   129  	var flags = unix.UMOUNT_NOFOLLOW
   130  	if len(path) == 0 {
   131  		return errors.New("path cannot be empty")
   132  	}
   133  	if force && lazy {
   134  		return errors.New("MNT_FORCE and MNT_DETACH (lazy unmount) cannot both be set")
   135  	}
   136  	if force {
   137  		flags |= unix.MNT_FORCE
   138  	}
   139  	if lazy {
   140  		flags |= unix.MNT_DETACH
   141  	}
   142  	if err := unix.Unmount(path, flags); err != nil {
   143  		return fmt.Errorf("umount %q flags %x: %v", path, flags, err)
   144  	}
   145  	return nil
   146  }