top_unix.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. //+build !windows
  2. package daemon
  3. import (
  4. "os/exec"
  5. "strconv"
  6. "strings"
  7. "github.com/docker/docker/api/types"
  8. derr "github.com/docker/docker/errors"
  9. )
  10. // ContainerTop lists the processes running inside of the given
  11. // container by calling ps with the given args, or with the flags
  12. // "-ef" if no args are given. An error is returned if the container
  13. // is not found, or is not running, or if there are any problems
  14. // running ps, or parsing the output.
  15. func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
  16. if psArgs == "" {
  17. psArgs = "-ef"
  18. }
  19. container, err := daemon.Get(name)
  20. if err != nil {
  21. return nil, err
  22. }
  23. if !container.IsRunning() {
  24. return nil, derr.ErrorCodeNotRunning.WithArgs(name)
  25. }
  26. pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID)
  27. if err != nil {
  28. return nil, err
  29. }
  30. output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output()
  31. if err != nil {
  32. return nil, derr.ErrorCodePSError.WithArgs(err)
  33. }
  34. procList := &types.ContainerProcessList{}
  35. lines := strings.Split(string(output), "\n")
  36. procList.Titles = strings.Fields(lines[0])
  37. pidIndex := -1
  38. for i, name := range procList.Titles {
  39. if name == "PID" {
  40. pidIndex = i
  41. }
  42. }
  43. if pidIndex == -1 {
  44. return nil, derr.ErrorCodeNoPID
  45. }
  46. // loop through the output and extract the PID from each line
  47. for _, line := range lines[1:] {
  48. if len(line) == 0 {
  49. continue
  50. }
  51. fields := strings.Fields(line)
  52. p, err := strconv.Atoi(fields[pidIndex])
  53. if err != nil {
  54. return nil, derr.ErrorCodeBadPID.WithArgs(fields[pidIndex], err)
  55. }
  56. for _, pid := range pids {
  57. if pid == p {
  58. // Make sure number of fields equals number of header titles
  59. // merging "overhanging" fields
  60. process := fields[:len(procList.Titles)-1]
  61. process = append(process, strings.Join(fields[len(procList.Titles)-1:], " "))
  62. procList.Processes = append(procList.Processes, process)
  63. }
  64. }
  65. }
  66. container.logEvent("top")
  67. return procList, nil
  68. }