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