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

     1  package mount
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  var flags = map[string]struct {
     9  	clear bool
    10  	flag  int
    11  }{
    12  	"defaults":      {false, 0},
    13  	"ro":            {false, RDONLY},
    14  	"rw":            {true, RDONLY},
    15  	"suid":          {true, NOSUID},
    16  	"nosuid":        {false, NOSUID},
    17  	"dev":           {true, NODEV},
    18  	"nodev":         {false, NODEV},
    19  	"exec":          {true, NOEXEC},
    20  	"noexec":        {false, NOEXEC},
    21  	"sync":          {false, SYNCHRONOUS},
    22  	"async":         {true, SYNCHRONOUS},
    23  	"dirsync":       {false, DIRSYNC},
    24  	"remount":       {false, REMOUNT},
    25  	"mand":          {false, MANDLOCK},
    26  	"nomand":        {true, MANDLOCK},
    27  	"atime":         {true, NOATIME},
    28  	"noatime":       {false, NOATIME},
    29  	"diratime":      {true, NODIRATIME},
    30  	"nodiratime":    {false, NODIRATIME},
    31  	"bind":          {false, BIND},
    32  	"rbind":         {false, RBIND},
    33  	"unbindable":    {false, UNBINDABLE},
    34  	"runbindable":   {false, RUNBINDABLE},
    35  	"private":       {false, PRIVATE},
    36  	"rprivate":      {false, RPRIVATE},
    37  	"shared":        {false, SHARED},
    38  	"rshared":       {false, RSHARED},
    39  	"slave":         {false, SLAVE},
    40  	"rslave":        {false, RSLAVE},
    41  	"relatime":      {false, RELATIME},
    42  	"norelatime":    {true, RELATIME},
    43  	"strictatime":   {false, STRICTATIME},
    44  	"nostrictatime": {true, STRICTATIME},
    45  }
    46  
    47  var validFlags = map[string]bool{
    48  	"":          true,
    49  	"size":      true,
    50  	"mode":      true,
    51  	"uid":       true,
    52  	"gid":       true,
    53  	"nr_inodes": true,
    54  	"nr_blocks": true,
    55  	"mpol":      true,
    56  }
    57  
    58  var propagationFlags = map[string]bool{
    59  	"bind":        true,
    60  	"rbind":       true,
    61  	"unbindable":  true,
    62  	"runbindable": true,
    63  	"private":     true,
    64  	"rprivate":    true,
    65  	"shared":      true,
    66  	"rshared":     true,
    67  	"slave":       true,
    68  	"rslave":      true,
    69  }
    70  
    71  // MergeTmpfsOptions merge mount options to make sure there is no duplicate.
    72  func MergeTmpfsOptions(options []string) ([]string, error) {
    73  	// We use collisions maps to remove duplicates.
    74  	// For flag, the key is the flag value (the key for propagation flag is -1)
    75  	// For data=value, the key is the data
    76  	flagCollisions := map[int]bool{}
    77  	dataCollisions := map[string]bool{}
    78  
    79  	var newOptions []string
    80  	// We process in reverse order
    81  	for i := len(options) - 1; i >= 0; i-- {
    82  		option := options[i]
    83  		if option == "defaults" {
    84  			continue
    85  		}
    86  		if f, ok := flags[option]; ok && f.flag != 0 {
    87  			// There is only one propagation mode
    88  			key := f.flag
    89  			if propagationFlags[option] {
    90  				key = -1
    91  			}
    92  			// Check to see if there is collision for flag
    93  			if !flagCollisions[key] {
    94  				// We prepend the option and add to collision map
    95  				newOptions = append([]string{option}, newOptions...)
    96  				flagCollisions[key] = true
    97  			}
    98  			continue
    99  		}
   100  		opt := strings.SplitN(option, "=", 2)
   101  		if len(opt) != 2 || !validFlags[opt[0]] {
   102  			return nil, fmt.Errorf("Invalid tmpfs option %q", opt)
   103  		}
   104  		if !dataCollisions[opt[0]] {
   105  			// We prepend the option and add to collision map
   106  			newOptions = append([]string{option}, newOptions...)
   107  			dataCollisions[opt[0]] = true
   108  		}
   109  	}
   110  
   111  	return newOptions, nil
   112  }
   113  
   114  // Parse fstab type mount options into mount() flags
   115  // and device specific data
   116  func parseOptions(options string) (int, string) {
   117  	var (
   118  		flag int
   119  		data []string
   120  	)
   121  
   122  	for _, o := range strings.Split(options, ",") {
   123  		// If the option does not exist in the flags table or the flag
   124  		// is not supported on the platform,
   125  		// then it is a data value for a specific fs type
   126  		if f, exists := flags[o]; exists && f.flag != 0 {
   127  			if f.clear {
   128  				flag &= ^f.flag
   129  			} else {
   130  				flag |= f.flag
   131  			}
   132  		} else {
   133  			data = append(data, o)
   134  		}
   135  	}
   136  	return flag, strings.Join(data, ",")
   137  }
   138  
   139  // ParseTmpfsOptions parse fstab type mount options into flags and data
   140  func ParseTmpfsOptions(options string) (int, string, error) {
   141  	flags, data := parseOptions(options)
   142  	for _, o := range strings.Split(data, ",") {
   143  		opt := strings.SplitN(o, "=", 2)
   144  		if !validFlags[opt[0]] {
   145  			return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt)
   146  		}
   147  	}
   148  	return flags, data, nil
   149  }