ps.go#Action
Action: func(context *cli.Context) error { if err := checkArgs(context, 1, minArgs); err != nil { return err } rootlessCg, err := shouldUseRootlessCgroupManager(context) if err != nil { return err } if rootlessCg { logrus.Warn("runc ps may fail if you don't have the full access to cgroups") } container, err := getContainer(context) if err != nil { return err } // ********************************** NOTICE ********************************** // pids, err := container.Processes() // ********************************** NOTICE ********************************** // if err != nil { return err } switch context.String("format") { case "table": case "json": return json.NewEncoder(os.Stdout).Encode(pids) default: return fmt.Errorf("invalid format option") } // [1:] is to remove command name, ex: // context.Args(): [containet_id ps_arg1 ps_arg2 ...] // psArgs: [ps_arg1 ps_arg2 ...] // psArgs := context.Args()[1:] if len(psArgs) == 0 { psArgs = []string{"-ef"} } // 在宿主机上运行ps命令 cmd := exec.Command("ps", psArgs...) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("%s: %s", err, output) } lines := strings.Split(string(output), "\n") pidIndex, err := getPidIndex(lines[0]) if err != nil { return err } fmt.Println(lines[0]) for _, line := range lines[1:] { if len(line) == 0 { continue } fields := strings.Fields(line) p, err := strconv.Atoi(fields[pidIndex]) if err != nil { return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err) } for _, pid := range pids { if pid == p { fmt.Println(line) break } } } return nil },
1) libcontainer/container_linux.go#linuxContainer.Processes
func (c *linuxContainer) Processes() ([]int, error) { pids, err := c.cgroupManager.GetAllPids() if err != nil { return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups") } return pids, nil}
1.1) libcontainer/cgroups/fs/apply_raw.go#Manager.GetAllPids
func (m *Manager) GetAllPids() ([]int, error) { paths := m.GetPaths() return cgroups.GetAllPids(paths["devices"])}func (m *Manager) GetPaths() map[string]string { m.mu.Lock() paths := m.Paths m.mu.Unlock() return paths}
1.1.1) libcontainer/cgroups/utils.go#GetAllPids
// GetAllPids returns all pids, that were added to cgroup at path and to all its// subcgroups.func GetAllPids(path string) ([]int, error) { var pids []int // collect pids from all sub-cgroups err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error { dir, file := filepath.Split(p) if file != CgroupProcesses { return nil } if iErr != nil { return iErr } cPids, err := readProcsFile(dir) if err != nil { return err } pids = append(pids, cPids...) return nil }) return pids, err}const CgroupProcesses = "cgroup.procs"func readProcsFile(dir string) ([]int, error) { f, err := os.Open(filepath.Join(dir, CgroupProcesses)) if err != nil { return nil, err } defer f.Close() var ( s = bufio.NewScanner(f) out = []int{} ) for s.Scan() { if t := s.Text(); t != "" { pid, err := strconv.Atoi(t) if err != nil { return nil, err } out = append(out, pid) } } return out, nil}