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 }