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