proc.go 4.7 KB

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