blob: 8a8430147ea5c231a3832a1e7de032b47b5fd97d [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// Copyright 2018 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 "bytes"
18 "fmt"
19 "io/ioutil"
20 "os"
21 "strconv"
22 "strings"
23
24 "github.com/prometheus/procfs/internal/fs"
25)
26
27// Proc provides information about a running process.
28type Proc struct {
29 // The process ID.
30 PID int
31
32 fs fs.FS
33}
34
35// Procs represents a list of Proc structs.
36type Procs []Proc
37
38func (p Procs) Len() int { return len(p) }
39func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
40func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }
41
42// Self returns a process for the current process read via /proc/self.
43func Self() (Proc, error) {
44 fs, err := NewFS(DefaultMountPoint)
45 if err != nil {
46 return Proc{}, err
47 }
48 return fs.Self()
49}
50
51// NewProc returns a process for the given pid under /proc.
52func NewProc(pid int) (Proc, error) {
53 fs, err := NewFS(DefaultMountPoint)
54 if err != nil {
55 return Proc{}, err
56 }
57 return fs.Proc(pid)
58}
59
60// AllProcs returns a list of all currently available processes under /proc.
61func AllProcs() (Procs, error) {
62 fs, err := NewFS(DefaultMountPoint)
63 if err != nil {
64 return Procs{}, err
65 }
66 return fs.AllProcs()
67}
68
69// Self returns a process for the current process.
70func (fs FS) Self() (Proc, error) {
71 p, err := os.Readlink(fs.proc.Path("self"))
72 if err != nil {
73 return Proc{}, err
74 }
75 pid, err := strconv.Atoi(strings.Replace(p, string(fs.proc), "", -1))
76 if err != nil {
77 return Proc{}, err
78 }
79 return fs.Proc(pid)
80}
81
82// NewProc returns a process for the given pid.
83//
84// Deprecated: use fs.Proc() instead
85func (fs FS) NewProc(pid int) (Proc, error) {
86 return fs.Proc(pid)
87}
88
89// Proc returns a process for the given pid.
90func (fs FS) Proc(pid int) (Proc, error) {
91 if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil {
92 return Proc{}, err
93 }
94 return Proc{PID: pid, fs: fs.proc}, nil
95}
96
97// AllProcs returns a list of all currently available processes.
98func (fs FS) AllProcs() (Procs, error) {
99 d, err := os.Open(fs.proc.Path())
100 if err != nil {
101 return Procs{}, err
102 }
103 defer d.Close()
104
105 names, err := d.Readdirnames(-1)
106 if err != nil {
107 return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
108 }
109
110 p := Procs{}
111 for _, n := range names {
112 pid, err := strconv.ParseInt(n, 10, 64)
113 if err != nil {
114 continue
115 }
116 p = append(p, Proc{PID: int(pid), fs: fs.proc})
117 }
118
119 return p, nil
120}
121
122// CmdLine returns the command line of a process.
123func (p Proc) CmdLine() ([]string, error) {
124 f, err := os.Open(p.path("cmdline"))
125 if err != nil {
126 return nil, err
127 }
128 defer f.Close()
129
130 data, err := ioutil.ReadAll(f)
131 if err != nil {
132 return nil, err
133 }
134
135 if len(data) < 1 {
136 return []string{}, nil
137 }
138
139 return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
140}
141
142// Comm returns the command name of a process.
143func (p Proc) Comm() (string, error) {
144 f, err := os.Open(p.path("comm"))
145 if err != nil {
146 return "", err
147 }
148 defer f.Close()
149
150 data, err := ioutil.ReadAll(f)
151 if err != nil {
152 return "", err
153 }
154
155 return strings.TrimSpace(string(data)), nil
156}
157
158// Executable returns the absolute path of the executable command of a process.
159func (p Proc) Executable() (string, error) {
160 exe, err := os.Readlink(p.path("exe"))
161 if os.IsNotExist(err) {
162 return "", nil
163 }
164
165 return exe, err
166}
167
168// Cwd returns the absolute path to the current working directory of the process.
169func (p Proc) Cwd() (string, error) {
170 wd, err := os.Readlink(p.path("cwd"))
171 if os.IsNotExist(err) {
172 return "", nil
173 }
174
175 return wd, err
176}
177
178// RootDir returns the absolute path to the process's root directory (as set by chroot)
179func (p Proc) RootDir() (string, error) {
180 rdir, err := os.Readlink(p.path("root"))
181 if os.IsNotExist(err) {
182 return "", nil
183 }
184
185 return rdir, err
186}
187
188// FileDescriptors returns the currently open file descriptors of a process.
189func (p Proc) FileDescriptors() ([]uintptr, error) {
190 names, err := p.fileDescriptors()
191 if err != nil {
192 return nil, err
193 }
194
195 fds := make([]uintptr, len(names))
196 for i, n := range names {
197 fd, err := strconv.ParseInt(n, 10, 32)
198 if err != nil {
199 return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
200 }
201 fds[i] = uintptr(fd)
202 }
203
204 return fds, nil
205}
206
207// FileDescriptorTargets returns the targets of all file descriptors of a process.
208// If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string.
209func (p Proc) FileDescriptorTargets() ([]string, error) {
210 names, err := p.fileDescriptors()
211 if err != nil {
212 return nil, err
213 }
214
215 targets := make([]string, len(names))
216
217 for i, name := range names {
218 target, err := os.Readlink(p.path("fd", name))
219 if err == nil {
220 targets[i] = target
221 }
222 }
223
224 return targets, nil
225}
226
227// FileDescriptorsLen returns the number of currently open file descriptors of
228// a process.
229func (p Proc) FileDescriptorsLen() (int, error) {
230 fds, err := p.fileDescriptors()
231 if err != nil {
232 return 0, err
233 }
234
235 return len(fds), nil
236}
237
238// MountStats retrieves statistics and configuration for mount points in a
239// process's namespace.
240func (p Proc) MountStats() ([]*Mount, error) {
241 f, err := os.Open(p.path("mountstats"))
242 if err != nil {
243 return nil, err
244 }
245 defer f.Close()
246
247 return parseMountStats(f)
248}
249
250func (p Proc) fileDescriptors() ([]string, error) {
251 d, err := os.Open(p.path("fd"))
252 if err != nil {
253 return nil, err
254 }
255 defer d.Close()
256
257 names, err := d.Readdirnames(-1)
258 if err != nil {
259 return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
260 }
261
262 return names, nil
263}
264
265func (p Proc) path(pa ...string) string {
266 return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
267}