blob: fa761b35295edea9173976a677f27dba1b5c9cb7 [file] [log] [blame]
khenaidoo26721882021-08-11 17:42:52 -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
khenaidoo26721882021-08-11 17:42:52 -040025var (
26 rPos = regexp.MustCompile(`^pos:\s+(\d+)$`)
27 rFlags = regexp.MustCompile(`^flags:\s+(\d+)$`)
28 rMntID = regexp.MustCompile(`^mnt_id:\s+(\d+)$`)
Abhay Kumar40252eb2025-10-13 13:25:53 +000029 rIno = regexp.MustCompile(`^ino:\s+(\d+)$`)
khenaidoo26721882021-08-11 17:42:52 -040030 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
Abhay Kumar40252eb2025-10-13 13:25:53 +000044 // Inode number
45 Ino string
khenaidoo26721882021-08-11 17:42:52 -040046 // List of inotify lines (structured) in the fdinfo file (kernel 3.8+ only)
47 InotifyInfos []InotifyInfo
48}
49
50// FDInfo constructor. On kernels older than 3.8, InotifyInfos will always be empty.
51func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) {
52 data, err := util.ReadFileNoStat(p.path("fdinfo", fd))
53 if err != nil {
54 return nil, err
55 }
56
Abhay Kumar40252eb2025-10-13 13:25:53 +000057 var text, pos, flags, mntid, ino string
khenaidoo26721882021-08-11 17:42:52 -040058 var inotify []InotifyInfo
59
60 scanner := bufio.NewScanner(bytes.NewReader(data))
61 for scanner.Scan() {
62 text = scanner.Text()
63 if rPos.MatchString(text) {
64 pos = rPos.FindStringSubmatch(text)[1]
65 } else if rFlags.MatchString(text) {
66 flags = rFlags.FindStringSubmatch(text)[1]
67 } else if rMntID.MatchString(text) {
68 mntid = rMntID.FindStringSubmatch(text)[1]
Abhay Kumar40252eb2025-10-13 13:25:53 +000069 } else if rIno.MatchString(text) {
70 ino = rIno.FindStringSubmatch(text)[1]
khenaidoo26721882021-08-11 17:42:52 -040071 } else if rInotify.MatchString(text) {
72 newInotify, err := parseInotifyInfo(text)
73 if err != nil {
74 return nil, err
75 }
76 inotify = append(inotify, *newInotify)
77 }
78 }
79
80 i := &ProcFDInfo{
81 FD: fd,
82 Pos: pos,
83 Flags: flags,
84 MntID: mntid,
Abhay Kumar40252eb2025-10-13 13:25:53 +000085 Ino: ino,
khenaidoo26721882021-08-11 17:42:52 -040086 InotifyInfos: inotify,
87 }
88
89 return i, nil
90}
91
92// InotifyInfo represents a single inotify line in the fdinfo file.
93type InotifyInfo struct {
94 // Watch descriptor number
95 WD string
96 // Inode number
97 Ino string
98 // Device ID
99 Sdev string
100 // Mask of events being monitored
101 Mask string
102}
103
104// InotifyInfo constructor. Only available on kernel 3.8+.
105func parseInotifyInfo(line string) (*InotifyInfo, error) {
106 m := rInotifyParts.FindStringSubmatch(line)
107 if len(m) >= 4 {
108 var mask string
109 if len(m) == 5 {
110 mask = m[4]
111 }
112 i := &InotifyInfo{
113 WD: m[1],
114 Ino: m[2],
115 Sdev: m[3],
116 Mask: mask,
117 }
118 return i, nil
119 }
Abhay Kumar40252eb2025-10-13 13:25:53 +0000120 return nil, fmt.Errorf("%w: invalid inode entry: %q", ErrFileParse, line)
khenaidoo26721882021-08-11 17:42:52 -0400121}
122
123// ProcFDInfos represents a list of ProcFDInfo structs.
124type ProcFDInfos []ProcFDInfo
125
126func (p ProcFDInfos) Len() int { return len(p) }
127func (p ProcFDInfos) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
128func (p ProcFDInfos) Less(i, j int) bool { return p[i].FD < p[j].FD }
129
Abhay Kumar40252eb2025-10-13 13:25:53 +0000130// InotifyWatchLen returns the total number of inotify watches.
khenaidoo26721882021-08-11 17:42:52 -0400131func (p ProcFDInfos) InotifyWatchLen() (int, error) {
132 length := 0
133 for _, f := range p {
134 length += len(f.InotifyInfos)
135 }
136
137 return length, nil
138}