proc.go 5.8 KB

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