ps.go#Action

  1. Action: func(context *cli.Context) error {
  2. if err := checkArgs(context, 1, minArgs); err != nil {
  3. return err
  4. }
  5. rootlessCg, err := shouldUseRootlessCgroupManager(context)
  6. if err != nil {
  7. return err
  8. }
  9. if rootlessCg {
  10. logrus.Warn("runc ps may fail if you don't have the full access to cgroups")
  11. }
  12. container, err := getContainer(context)
  13. if err != nil {
  14. return err
  15. }
  16. // ********************************** NOTICE ********************************** //
  17. pids, err := container.Processes()
  18. // ********************************** NOTICE ********************************** //
  19. if err != nil {
  20. return err
  21. }
  22. switch context.String("format") {
  23. case "table":
  24. case "json":
  25. return json.NewEncoder(os.Stdout).Encode(pids)
  26. default:
  27. return fmt.Errorf("invalid format option")
  28. }
  29. // [1:] is to remove command name, ex:
  30. // context.Args(): [containet_id ps_arg1 ps_arg2 ...]
  31. // psArgs: [ps_arg1 ps_arg2 ...]
  32. //
  33. psArgs := context.Args()[1:]
  34. if len(psArgs) == 0 {
  35. psArgs = []string{"-ef"}
  36. }
  37. // 在宿主机上运行ps命令
  38. cmd := exec.Command("ps", psArgs...)
  39. output, err := cmd.CombinedOutput()
  40. if err != nil {
  41. return fmt.Errorf("%s: %s", err, output)
  42. }
  43. lines := strings.Split(string(output), "\n")
  44. pidIndex, err := getPidIndex(lines[0])
  45. if err != nil {
  46. return err
  47. }
  48. fmt.Println(lines[0])
  49. for _, line := range lines[1:] {
  50. if len(line) == 0 {
  51. continue
  52. }
  53. fields := strings.Fields(line)
  54. p, err := strconv.Atoi(fields[pidIndex])
  55. if err != nil {
  56. return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err)
  57. }
  58. for _, pid := range pids {
  59. if pid == p {
  60. fmt.Println(line)
  61. break
  62. }
  63. }
  64. }
  65. return nil
  66. },

1) libcontainer/container_linux.go#linuxContainer.Processes

  1. func (c *linuxContainer) Processes() ([]int, error) {
  2. pids, err := c.cgroupManager.GetAllPids()
  3. if err != nil {
  4. return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups")
  5. }
  6. return pids, nil
  7. }

1.1) libcontainer/cgroups/fs/apply_raw.go#Manager.GetAllPids

  1. func (m *Manager) GetAllPids() ([]int, error) {
  2. paths := m.GetPaths()
  3. return cgroups.GetAllPids(paths["devices"])
  4. }
  5. func (m *Manager) GetPaths() map[string]string {
  6. m.mu.Lock()
  7. paths := m.Paths
  8. m.mu.Unlock()
  9. return paths
  10. }

1.1.1) libcontainer/cgroups/utils.go#GetAllPids

  1. // GetAllPids returns all pids, that were added to cgroup at path and to all its
  2. // subcgroups.
  3. func GetAllPids(path string) ([]int, error) {
  4. var pids []int
  5. // collect pids from all sub-cgroups
  6. err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error {
  7. dir, file := filepath.Split(p)
  8. if file != CgroupProcesses {
  9. return nil
  10. }
  11. if iErr != nil {
  12. return iErr
  13. }
  14. cPids, err := readProcsFile(dir)
  15. if err != nil {
  16. return err
  17. }
  18. pids = append(pids, cPids...)
  19. return nil
  20. })
  21. return pids, err
  22. }
  23. const CgroupProcesses = "cgroup.procs"
  24. func readProcsFile(dir string) ([]int, error) {
  25. f, err := os.Open(filepath.Join(dir, CgroupProcesses))
  26. if err != nil {
  27. return nil, err
  28. }
  29. defer f.Close()
  30. var (
  31. s = bufio.NewScanner(f)
  32. out = []int{}
  33. )
  34. for s.Scan() {
  35. if t := s.Text(); t != "" {
  36. pid, err := strconv.Atoi(t)
  37. if err != nil {
  38. return nil, err
  39. }
  40. out = append(out, pid)
  41. }
  42. }
  43. return out, nil
  44. }