本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
5.5KB

  1. // Copyright 2019 The Prometheus Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package procfs
  14. import (
  15. "bufio"
  16. "fmt"
  17. "io"
  18. "os"
  19. "strconv"
  20. "strings"
  21. )
  22. var validOptionalFields = map[string]bool{
  23. "shared": true,
  24. "master": true,
  25. "propagate_from": true,
  26. "unbindable": true,
  27. }
  28. // A MountInfo is a type that describes the details, options
  29. // for each mount, parsed from /proc/self/mountinfo.
  30. // The fields described in each entry of /proc/self/mountinfo
  31. // is described in the following man page.
  32. // http://man7.org/linux/man-pages/man5/proc.5.html
  33. type MountInfo struct {
  34. // Unique Id for the mount
  35. MountId int
  36. // The Id of the parent mount
  37. ParentId int
  38. // The value of `st_dev` for the files on this FS
  39. MajorMinorVer string
  40. // The pathname of the directory in the FS that forms
  41. // the root for this mount
  42. Root string
  43. // The pathname of the mount point relative to the root
  44. MountPoint string
  45. // Mount options
  46. Options map[string]string
  47. // Zero or more optional fields
  48. OptionalFields map[string]string
  49. // The Filesystem type
  50. FSType string
  51. // FS specific information or "none"
  52. Source string
  53. // Superblock options
  54. SuperOptions map[string]string
  55. }
  56. // Returns part of the mountinfo line, if it exists, else an empty string.
  57. func getStringSliceElement(parts []string, idx int, defaultValue string) string {
  58. if idx >= len(parts) {
  59. return defaultValue
  60. }
  61. return parts[idx]
  62. }
  63. // Reads each line of the mountinfo file, and returns a list of formatted MountInfo structs.
  64. func parseMountInfo(r io.Reader) ([]*MountInfo, error) {
  65. mounts := []*MountInfo{}
  66. scanner := bufio.NewScanner(r)
  67. for scanner.Scan() {
  68. mountString := scanner.Text()
  69. parsedMounts, err := parseMountInfoString(mountString)
  70. if err != nil {
  71. return nil, err
  72. }
  73. mounts = append(mounts, parsedMounts)
  74. }
  75. err := scanner.Err()
  76. return mounts, err
  77. }
  78. // Parses a mountinfo file line, and converts it to a MountInfo struct.
  79. // An important check here is to see if the hyphen separator, as if it does not exist,
  80. // it means that the line is malformed.
  81. func parseMountInfoString(mountString string) (*MountInfo, error) {
  82. var err error
  83. // OptionalFields can be zero, hence these checks to ensure we do not populate the wrong values in the wrong spots
  84. separatorIndex := strings.Index(mountString, "-")
  85. if separatorIndex == -1 {
  86. return nil, fmt.Errorf("no separator found in mountinfo string: %s", mountString)
  87. }
  88. beforeFields := strings.Fields(mountString[:separatorIndex])
  89. afterFields := strings.Fields(mountString[separatorIndex+1:])
  90. if (len(beforeFields) + len(afterFields)) < 7 {
  91. return nil, fmt.Errorf("too few fields")
  92. }
  93. mount := &MountInfo{
  94. MajorMinorVer: getStringSliceElement(beforeFields, 2, ""),
  95. Root: getStringSliceElement(beforeFields, 3, ""),
  96. MountPoint: getStringSliceElement(beforeFields, 4, ""),
  97. Options: mountOptionsParser(getStringSliceElement(beforeFields, 5, "")),
  98. OptionalFields: nil,
  99. FSType: getStringSliceElement(afterFields, 0, ""),
  100. Source: getStringSliceElement(afterFields, 1, ""),
  101. SuperOptions: mountOptionsParser(getStringSliceElement(afterFields, 2, "")),
  102. }
  103. mount.MountId, err = strconv.Atoi(getStringSliceElement(beforeFields, 0, ""))
  104. if err != nil {
  105. return nil, fmt.Errorf("failed to parse mount ID")
  106. }
  107. mount.ParentId, err = strconv.Atoi(getStringSliceElement(beforeFields, 1, ""))
  108. if err != nil {
  109. return nil, fmt.Errorf("failed to parse parent ID")
  110. }
  111. // Has optional fields, which is a space separated list of values.
  112. // Example: shared:2 master:7
  113. if len(beforeFields) > 6 {
  114. mount.OptionalFields = make(map[string]string)
  115. optionalFields := beforeFields[6:]
  116. for _, field := range optionalFields {
  117. optionSplit := strings.Split(field, ":")
  118. target, value := optionSplit[0], ""
  119. if len(optionSplit) == 2 {
  120. value = optionSplit[1]
  121. }
  122. // Checks if the 'keys' in the optional fields in the mountinfo line are acceptable.
  123. // Allowed 'keys' are shared, master, propagate_from, unbindable.
  124. if _, ok := validOptionalFields[target]; ok {
  125. mount.OptionalFields[target] = value
  126. }
  127. }
  128. }
  129. return mount, nil
  130. }
  131. // Parses the mount options, superblock options.
  132. func mountOptionsParser(mountOptions string) map[string]string {
  133. opts := make(map[string]string)
  134. options := strings.Split(mountOptions, ",")
  135. for _, opt := range options {
  136. splitOption := strings.Split(opt, "=")
  137. if len(splitOption) < 2 {
  138. key := splitOption[0]
  139. opts[key] = ""
  140. } else {
  141. key, value := splitOption[0], splitOption[1]
  142. opts[key] = value
  143. }
  144. }
  145. return opts
  146. }
  147. // Retrieves mountinfo information from `/proc/self/mountinfo`.
  148. func GetMounts() ([]*MountInfo, error) {
  149. f, err := os.Open("/proc/self/mountinfo")
  150. if err != nil {
  151. return nil, err
  152. }
  153. defer f.Close()
  154. return parseMountInfo(f)
  155. }
  156. // Retrieves mountinfo information from a processes' `/proc/<pid>/mountinfo`.
  157. func GetProcMounts(pid int) ([]*MountInfo, error) {
  158. f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
  159. if err != nil {
  160. return nil, err
  161. }
  162. defer f.Close()
  163. return parseMountInfo(f)
  164. }
上海开阖软件有限公司 沪ICP备12045867号-1