proc.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. // FileDescriptors returns the currently open file descriptors of a process.
  135. func (p Proc) FileDescriptors() ([]uintptr, error) {
  136. names, err := p.fileDescriptors()
  137. if err != nil {
  138. return nil, err
  139. }
  140. fds := make([]uintptr, len(names))
  141. for i, n := range names {
  142. fd, err := strconv.ParseInt(n, 10, 32)
  143. if err != nil {
  144. return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
  145. }
  146. fds[i] = uintptr(fd)
  147. }
  148. return fds, nil
  149. }
  150. // FileDescriptorTargets returns the targets of all file descriptors of a process.
  151. // If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string.
  152. func (p Proc) FileDescriptorTargets() ([]string, error) {
  153. names, err := p.fileDescriptors()
  154. if err != nil {
  155. return nil, err
  156. }
  157. targets := make([]string, len(names))
  158. for i, name := range names {
  159. target, err := os.Readlink(p.path("fd", name))
  160. if err == nil {
  161. targets[i] = target
  162. }
  163. }
  164. return targets, nil
  165. }
  166. // FileDescriptorsLen returns the number of currently open file descriptors of
  167. // a process.
  168. func (p Proc) FileDescriptorsLen() (int, error) {
  169. fds, err := p.fileDescriptors()
  170. if err != nil {
  171. return 0, err
  172. }
  173. return len(fds), nil
  174. }
  175. // MountStats retrieves statistics and configuration for mount points in a
  176. // process's namespace.
  177. func (p Proc) MountStats() ([]*Mount, error) {
  178. f, err := os.Open(p.path("mountstats"))
  179. if err != nil {
  180. return nil, err
  181. }
  182. defer f.Close()
  183. return parseMountStats(f)
  184. }
  185. func (p Proc) fileDescriptors() ([]string, error) {
  186. d, err := os.Open(p.path("fd"))
  187. if err != nil {
  188. return nil, err
  189. }
  190. defer d.Close()
  191. names, err := d.Readdirnames(-1)
  192. if err != nil {
  193. return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
  194. }
  195. return names, nil
  196. }
  197. func (p Proc) path(pa ...string) string {
  198. return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
  199. }