You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

proc.go 7.0KB

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