flags.go 3.9 KB

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