您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

320 行
7.3 KiB

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