13
"github.com/containers/podman/v5/libpod/define"
14
"github.com/containers/podman/v5/pkg/util"
15
"github.com/google/shlex"
16
"github.com/sirupsen/logrus"
19
var isDescriptor = map[string]bool{}
22
allDescriptors, err := util.GetContainerPidInformationDescriptors()
24
// Should never happen
25
logrus.Debugf("failed call to util.GetContainerPidInformationDescriptors()")
28
for _, d := range allDescriptors {
29
isDescriptor[d] = true
33
// Top gathers statistics about the running processes in a container. It returns a
35
func (c *Container) Top(descriptors []string) ([]string, error) {
36
conStat, err := c.State()
38
return nil, fmt.Errorf("unable to look up state for %s: %w", c.ID(), err)
40
if conStat != define.ContainerStateRunning {
41
return nil, errors.New("top can only be used on running containers")
44
// Default to 'ps -ef' compatible descriptors
45
if len(strings.Join(descriptors, "")) == 0 {
46
descriptors = []string{"user", "pid", "ppid", "pcpu", "etime", "tty", "time", "args"}
49
// If everything in descriptors is a supported AIX format
50
// descriptor, we use 'ps -ao <descriptors>', otherwise we pass
51
// everything straight through to ps.
52
supportedDescriptors := true
53
for _, d := range descriptors {
54
if _, ok := isDescriptor[d]; !ok {
55
supportedDescriptors = false
59
if supportedDescriptors {
60
descriptors = []string{"-ao", strings.Join(descriptors, ",")}
63
// Note that the descriptors to ps(1) must be shlexed (see #12452).
64
psDescriptors := []string{}
65
for _, d := range descriptors {
66
shSplit, err := shlex.Split(d)
68
return nil, fmt.Errorf("parsing ps args: %w", err)
70
for _, s := range shSplit {
72
psDescriptors = append(psDescriptors, s)
77
jailName, err := c.jailName()
79
return nil, fmt.Errorf("getting jail name: %w", err)
86
args = append(args, psDescriptors...)
88
output, err := execPS(args)
90
return nil, fmt.Errorf("executing ps(1): %w", err)
96
func execPS(args []string) ([]string, error) {
97
cmd := exec.Command("ps", args...)
98
stdoutPipe, err := cmd.StdoutPipe()
102
stderrPipe, err := cmd.StderrPipe()
107
var wg sync.WaitGroup
111
scanner := bufio.NewScanner(stdoutPipe)
113
stdout = append(stdout, scanner.Text())
119
scanner := bufio.NewScanner(stderrPipe)
121
stderr = append(stderr, scanner.Text())
126
if err := cmd.Start(); err != nil {
130
if err := cmd.Wait(); err != nil {
131
return nil, fmt.Errorf("ps(1) command failed: %w, output: %s", err, strings.Join(stderr, " "))