1
2
3
4
5
6
7
8
9
10
11
12
13
14 package procfs
15
16 import (
17 "bytes"
18 "errors"
19 "fmt"
20 "io"
21 "os"
22 "strconv"
23 "strings"
24
25 "github.com/prometheus/procfs/internal/util"
26 )
27
28
29 type Proc struct {
30
31 PID int
32
33 fs FS
34 }
35
36
37 type Procs []Proc
38
39 var (
40 ErrFileParse = errors.New("Error Parsing File")
41 ErrFileRead = errors.New("Error Reading File")
42 ErrMountPoint = errors.New("Error Accessing Mount point")
43 )
44
45 func (p Procs) Len() int { return len(p) }
46 func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
47 func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }
48
49
50 func Self() (Proc, error) {
51 fs, err := NewFS(DefaultMountPoint)
52 if err != nil || errors.Unwrap(err) == ErrMountPoint {
53 return Proc{}, err
54 }
55 return fs.Self()
56 }
57
58
59 func NewProc(pid int) (Proc, error) {
60 fs, err := NewFS(DefaultMountPoint)
61 if err != nil {
62 return Proc{}, err
63 }
64 return fs.Proc(pid)
65 }
66
67
68 func AllProcs() (Procs, error) {
69 fs, err := NewFS(DefaultMountPoint)
70 if err != nil {
71 return Procs{}, err
72 }
73 return fs.AllProcs()
74 }
75
76
77 func (fs FS) Self() (Proc, error) {
78 p, err := os.Readlink(fs.proc.Path("self"))
79 if err != nil {
80 return Proc{}, err
81 }
82 pid, err := strconv.Atoi(strings.Replace(p, string(fs.proc), "", -1))
83 if err != nil {
84 return Proc{}, err
85 }
86 return fs.Proc(pid)
87 }
88
89
90
91
92 func (fs FS) NewProc(pid int) (Proc, error) {
93 return fs.Proc(pid)
94 }
95
96
97 func (fs FS) Proc(pid int) (Proc, error) {
98 if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil {
99 return Proc{}, err
100 }
101 return Proc{PID: pid, fs: fs}, nil
102 }
103
104
105 func (fs FS) AllProcs() (Procs, error) {
106 d, err := os.Open(fs.proc.Path())
107 if err != nil {
108 return Procs{}, err
109 }
110 defer d.Close()
111
112 names, err := d.Readdirnames(-1)
113 if err != nil {
114 return Procs{}, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, names, err)
115 }
116
117 p := Procs{}
118 for _, n := range names {
119 pid, err := strconv.ParseInt(n, 10, 64)
120 if err != nil {
121 continue
122 }
123 p = append(p, Proc{PID: int(pid), fs: fs})
124 }
125
126 return p, nil
127 }
128
129
130 func (p Proc) CmdLine() ([]string, error) {
131 data, err := util.ReadFileNoStat(p.path("cmdline"))
132 if err != nil {
133 return nil, err
134 }
135
136 if len(data) < 1 {
137 return []string{}, nil
138 }
139
140 return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
141 }
142
143
144 func (p Proc) Wchan() (string, error) {
145 f, err := os.Open(p.path("wchan"))
146 if err != nil {
147 return "", err
148 }
149 defer f.Close()
150
151 data, err := io.ReadAll(f)
152 if err != nil {
153 return "", err
154 }
155
156 wchan := string(data)
157 if wchan == "" || wchan == "0" {
158 return "", nil
159 }
160
161 return wchan, nil
162 }
163
164
165 func (p Proc) Comm() (string, error) {
166 data, err := util.ReadFileNoStat(p.path("comm"))
167 if err != nil {
168 return "", err
169 }
170
171 return strings.TrimSpace(string(data)), nil
172 }
173
174
175 func (p Proc) Executable() (string, error) {
176 exe, err := os.Readlink(p.path("exe"))
177 if os.IsNotExist(err) {
178 return "", nil
179 }
180
181 return exe, err
182 }
183
184
185 func (p Proc) Cwd() (string, error) {
186 wd, err := os.Readlink(p.path("cwd"))
187 if os.IsNotExist(err) {
188 return "", nil
189 }
190
191 return wd, err
192 }
193
194
195 func (p Proc) RootDir() (string, error) {
196 rdir, err := os.Readlink(p.path("root"))
197 if os.IsNotExist(err) {
198 return "", nil
199 }
200
201 return rdir, err
202 }
203
204
205 func (p Proc) FileDescriptors() ([]uintptr, error) {
206 names, err := p.fileDescriptors()
207 if err != nil {
208 return nil, err
209 }
210
211 fds := make([]uintptr, len(names))
212 for i, n := range names {
213 fd, err := strconv.ParseInt(n, 10, 32)
214 if err != nil {
215 return nil, fmt.Errorf("%s: Cannot parse line: %v: %w", ErrFileParse, i, err)
216 }
217 fds[i] = uintptr(fd)
218 }
219
220 return fds, nil
221 }
222
223
224
225 func (p Proc) FileDescriptorTargets() ([]string, error) {
226 names, err := p.fileDescriptors()
227 if err != nil {
228 return nil, err
229 }
230
231 targets := make([]string, len(names))
232
233 for i, name := range names {
234 target, err := os.Readlink(p.path("fd", name))
235 if err == nil {
236 targets[i] = target
237 }
238 }
239
240 return targets, nil
241 }
242
243
244
245 func (p Proc) FileDescriptorsLen() (int, error) {
246
247 if p.fs.isReal {
248 stat, err := os.Stat(p.path("fd"))
249 if err != nil {
250 return 0, err
251 }
252
253 size := stat.Size()
254 if size > 0 {
255 return int(size), nil
256 }
257 }
258
259 fds, err := p.fileDescriptors()
260 if err != nil {
261 return 0, err
262 }
263
264 return len(fds), nil
265 }
266
267
268
269 func (p Proc) MountStats() ([]*Mount, error) {
270 f, err := os.Open(p.path("mountstats"))
271 if err != nil {
272 return nil, err
273 }
274 defer f.Close()
275
276 return parseMountStats(f)
277 }
278
279
280
281
282
283 func (p Proc) MountInfo() ([]*MountInfo, error) {
284 data, err := util.ReadFileNoStat(p.path("mountinfo"))
285 if err != nil {
286 return nil, err
287 }
288 return parseMountInfo(data)
289 }
290
291 func (p Proc) fileDescriptors() ([]string, error) {
292 d, err := os.Open(p.path("fd"))
293 if err != nil {
294 return nil, err
295 }
296 defer d.Close()
297
298 names, err := d.Readdirnames(-1)
299 if err != nil {
300 return nil, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, names, err)
301 }
302
303 return names, nil
304 }
305
306 func (p Proc) path(pa ...string) string {
307 return p.fs.proc.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
308 }
309
310
311
312 func (p Proc) FileDescriptorsInfo() (ProcFDInfos, error) {
313 names, err := p.fileDescriptors()
314 if err != nil {
315 return nil, err
316 }
317
318 var fdinfos ProcFDInfos
319
320 for _, n := range names {
321 fdinfo, err := p.FDInfo(n)
322 if err != nil {
323 continue
324 }
325 fdinfos = append(fdinfos, *fdinfo)
326 }
327
328 return fdinfos, nil
329 }
330
331
332 func (p Proc) Schedstat() (ProcSchedstat, error) {
333 contents, err := os.ReadFile(p.path("schedstat"))
334 if err != nil {
335 return ProcSchedstat{}, err
336 }
337 return parseProcSchedstat(string(contents))
338 }
339
View as plain text