proc.go 4.2 KB

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