proc_fdinfo.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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. "bytes"
  17. "fmt"
  18. "regexp"
  19. "github.com/prometheus/procfs/internal/util"
  20. )
  21. var (
  22. rPos = regexp.MustCompile(`^pos:\s+(\d+)$`)
  23. rFlags = regexp.MustCompile(`^flags:\s+(\d+)$`)
  24. rMntID = regexp.MustCompile(`^mnt_id:\s+(\d+)$`)
  25. rIno = regexp.MustCompile(`^ino:\s+(\d+)$`)
  26. rInotify = regexp.MustCompile(`^inotify`)
  27. rInotifyParts = regexp.MustCompile(`^inotify\s+wd:([0-9a-f]+)\s+ino:([0-9a-f]+)\s+sdev:([0-9a-f]+)(?:\s+mask:([0-9a-f]+))?`)
  28. )
  29. // ProcFDInfo contains represents file descriptor information.
  30. type ProcFDInfo struct {
  31. // File descriptor
  32. FD string
  33. // File offset
  34. Pos string
  35. // File access mode and status flags
  36. Flags string
  37. // Mount point ID
  38. MntID string
  39. // Inode number
  40. Ino string
  41. // List of inotify lines (structured) in the fdinfo file (kernel 3.8+ only)
  42. InotifyInfos []InotifyInfo
  43. }
  44. // FDInfo constructor. On kernels older than 3.8, InotifyInfos will always be empty.
  45. func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) {
  46. data, err := util.ReadFileNoStat(p.path("fdinfo", fd))
  47. if err != nil {
  48. return nil, err
  49. }
  50. var text, pos, flags, mntid, ino string
  51. var inotify []InotifyInfo
  52. scanner := bufio.NewScanner(bytes.NewReader(data))
  53. for scanner.Scan() {
  54. text = scanner.Text()
  55. if rPos.MatchString(text) {
  56. pos = rPos.FindStringSubmatch(text)[1]
  57. } else if rFlags.MatchString(text) {
  58. flags = rFlags.FindStringSubmatch(text)[1]
  59. } else if rMntID.MatchString(text) {
  60. mntid = rMntID.FindStringSubmatch(text)[1]
  61. } else if rIno.MatchString(text) {
  62. ino = rIno.FindStringSubmatch(text)[1]
  63. } else if rInotify.MatchString(text) {
  64. newInotify, err := parseInotifyInfo(text)
  65. if err != nil {
  66. return nil, err
  67. }
  68. inotify = append(inotify, *newInotify)
  69. }
  70. }
  71. i := &ProcFDInfo{
  72. FD: fd,
  73. Pos: pos,
  74. Flags: flags,
  75. MntID: mntid,
  76. Ino: ino,
  77. InotifyInfos: inotify,
  78. }
  79. return i, nil
  80. }
  81. // InotifyInfo represents a single inotify line in the fdinfo file.
  82. type InotifyInfo struct {
  83. // Watch descriptor number
  84. WD string
  85. // Inode number
  86. Ino string
  87. // Device ID
  88. Sdev string
  89. // Mask of events being monitored
  90. Mask string
  91. }
  92. // InotifyInfo constructor. Only available on kernel 3.8+.
  93. func parseInotifyInfo(line string) (*InotifyInfo, error) {
  94. m := rInotifyParts.FindStringSubmatch(line)
  95. if len(m) >= 4 {
  96. var mask string
  97. if len(m) == 5 {
  98. mask = m[4]
  99. }
  100. i := &InotifyInfo{
  101. WD: m[1],
  102. Ino: m[2],
  103. Sdev: m[3],
  104. Mask: mask,
  105. }
  106. return i, nil
  107. }
  108. return nil, fmt.Errorf("%w: invalid inode entry: %q", ErrFileParse, line)
  109. }
  110. // ProcFDInfos represents a list of ProcFDInfo structs.
  111. type ProcFDInfos []ProcFDInfo
  112. func (p ProcFDInfos) Len() int { return len(p) }
  113. func (p ProcFDInfos) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
  114. func (p ProcFDInfos) Less(i, j int) bool { return p[i].FD < p[j].FD }
  115. // InotifyWatchLen returns the total number of inotify watches.
  116. func (p ProcFDInfos) InotifyWatchLen() (int, error) {
  117. length := 0
  118. for _, f := range p {
  119. length += len(f.InotifyInfos)
  120. }
  121. return length, nil
  122. }