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