github.com/coreos/mantle@v0.13.0/system/mount_linux.go (about) 1 // Copyright 2015 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package system 16 17 import ( 18 "fmt" 19 "strings" 20 "syscall" 21 ) 22 23 const ( 24 // MS_PROPAGATION flags are special operations and cannot be combined 25 // with each other or any flags other than MS_REC. 26 MS_PROPAGATION = syscall.MS_SHARED | syscall.MS_SLAVE | syscall.MS_UNBINDABLE | syscall.MS_PRIVATE 27 // MS_OPERATION flags can be mapped to high level operation names. 28 MS_OPERATION = MS_PROPAGATION | syscall.MS_BIND | syscall.MS_MOVE | syscall.MS_REC 29 ) 30 31 // map mount flags to higher level "operation" names 32 var mountOps = map[uintptr]string{ 33 syscall.MS_BIND: "bind", 34 syscall.MS_BIND | syscall.MS_REC: "rbind", 35 syscall.MS_MOVE: "move", 36 syscall.MS_SILENT: "silent", 37 syscall.MS_UNBINDABLE: "unbindable", 38 syscall.MS_UNBINDABLE | syscall.MS_REC: "runbindable", 39 syscall.MS_PRIVATE: "private", 40 syscall.MS_PRIVATE | syscall.MS_REC: "rprivate", 41 syscall.MS_SLAVE: "slave", 42 syscall.MS_SLAVE | syscall.MS_REC: "rslave", 43 syscall.MS_SHARED: "shared", 44 syscall.MS_SHARED | syscall.MS_REC: "rshared", 45 } 46 47 // map mount flag strings to the numeric value. 48 // names match mount(8) except where otherwise noted 49 var mountFlags = map[string]uintptr{ 50 "ro": syscall.MS_RDONLY, 51 "nosuid": syscall.MS_NOSUID, 52 "nodev": syscall.MS_NODEV, 53 "noexec": syscall.MS_NOEXEC, 54 "sync": syscall.MS_SYNCHRONOUS, 55 "remount": syscall.MS_REMOUNT, 56 "mand": syscall.MS_MANDLOCK, 57 "dirsync": syscall.MS_DIRSYNC, 58 "noatime": syscall.MS_NOATIME, 59 "nodiratime": syscall.MS_NODIRATIME, 60 "bind": syscall.MS_BIND, 61 "rbind": syscall.MS_BIND | syscall.MS_REC, 62 "x-move": syscall.MS_MOVE, // --move 63 "silent": syscall.MS_SILENT, 64 "unbindable": syscall.MS_UNBINDABLE, 65 "runbindable": syscall.MS_UNBINDABLE | syscall.MS_REC, 66 "private": syscall.MS_PRIVATE, 67 "rprivate": syscall.MS_PRIVATE | syscall.MS_REC, 68 "slave": syscall.MS_SLAVE, 69 "rslave": syscall.MS_SLAVE | syscall.MS_REC, 70 "shared": syscall.MS_SHARED, 71 "rshared": syscall.MS_SHARED | syscall.MS_REC, 72 "relatime": syscall.MS_RELATIME, 73 "iversion": syscall.MS_I_VERSION, 74 "strictatime": syscall.MS_STRICTATIME, 75 } 76 77 // MountError records a mount operation failure, similar to os.PathError 78 type MountError struct { 79 Source string 80 Target string 81 FsType string 82 Flags uintptr 83 Extra string 84 Err error 85 } 86 87 func (e *MountError) Error() string { 88 op, ok := mountOps[e.Flags&MS_OPERATION] 89 if !ok { 90 op = "mount" 91 } 92 if e.Flags&MS_PROPAGATION != 0 { 93 // Source is unused for these operations. 94 return fmt.Sprintf("%s on %s failed: %v", op, e.Target, e.Err) 95 } 96 return fmt.Sprintf("%s %s to %s failed: %v", op, e.Source, e.Target, e.Err) 97 } 98 99 func splitFlags(options string) (uintptr, string) { 100 var flags uintptr 101 var extra []string 102 for _, opt := range strings.Split(options, ",") { 103 if flag, ok := mountFlags[opt]; ok { 104 flags |= flag 105 } else { 106 extra = append(extra, opt) 107 } 108 } 109 return flags, strings.Join(extra, ",") 110 } 111 112 func doMount(source, target, fstype string, flags uintptr, extra string) error { 113 if err := syscall.Mount(source, target, fstype, flags, extra); err != nil { 114 return &MountError{ 115 Source: source, 116 Target: target, 117 FsType: fstype, 118 Flags: flags, 119 Extra: extra, 120 Err: err, 121 } 122 } 123 return nil 124 } 125 126 // Mount wraps mount(2) in a similar way to mount(8), accepting both flags 127 // and filesystem options as a string. Any option not recognized as a flag 128 // will be passed as a filesystem option. Note that option parsing here is 129 // simpler than mount(8) and quotes are not considered. 130 func Mount(source, target, fstype, options string) error { 131 // A simple default for virtual filesystems 132 if source == "" { 133 source = fstype 134 } 135 flags, extra := splitFlags(options) 136 return doMount(source, target, fstype, flags, extra) 137 } 138 139 // Bind creates a bind mount from source to target. 140 func Bind(source, target string) error { 141 return doMount(source, target, "none", syscall.MS_BIND, "") 142 } 143 144 // ReadOnlyBind creates a read-only bind mount. Note that this must be 145 // performed in two operations so it is possible for a read-write bind 146 // to be left behind if the second operation fails. 147 func ReadOnlyBind(source, target string) error { 148 var flags uintptr = syscall.MS_BIND 149 if err := doMount(source, target, "none", flags, ""); err != nil { 150 return err 151 } 152 flags |= syscall.MS_REMOUNT | syscall.MS_RDONLY 153 return doMount(source, target, "none", flags, "") 154 } 155 156 // RecursiveBind bind mounts an entire tree under source to target. 157 func RecursiveBind(source, target string) error { 158 return doMount(source, target, "none", syscall.MS_BIND|syscall.MS_REC, "") 159 } 160 161 // Move moves an entire tree under the source mountpoint to target. 162 func Move(source, target string) error { 163 return doMount(source, target, "none", syscall.MS_MOVE, "") 164 } 165 166 // MountPrivate changes a mount point's propagation type to "private" 167 func MountPrivate(target string) error { 168 return doMount("none", target, "none", syscall.MS_PRIVATE, "") 169 } 170 171 // RecursivePrivate changes an entire tree's propagation type to "private" 172 func RecursivePrivate(target string) error { 173 return doMount("none", target, "none", syscall.MS_PRIVATE|syscall.MS_REC, "") 174 } 175 176 // MountShared changes a mount point's propagation type to "shared" 177 func MountShared(target string) error { 178 return doMount("none", target, "none", syscall.MS_SHARED, "") 179 } 180 181 // RecursiveShared changes an entire tree's propagation type to "shared" 182 func RecursiveShared(target string) error { 183 return doMount("none", target, "none", syscall.MS_SHARED|syscall.MS_REC, "") 184 } 185 186 // MountSlave changes a mount point's propagation type to "slave" 187 func MountSlave(target string) error { 188 return doMount("none", target, "none", syscall.MS_SLAVE, "") 189 } 190 191 // RecursiveSlave changes an entire tree's propagation type to "slave" 192 func RecursiveSlave(target string) error { 193 return doMount("none", target, "none", syscall.MS_SLAVE|syscall.MS_REC, "") 194 }