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  }