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 }