Files
podman/libpod/container_top_freebsd.go
Kir Kolyshkin b046387979 Inline the initial slice into append
Instead of creating a slice and then appending to it, let's inline the
initial slice into append. This may or may not result in less slice
reallocations, but it is silencing the prealloc linter warnings.

This commit is part of series fixing issues reported by prealloc linter
from golangci-lint v2.8.0.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-02-11 11:41:10 -08:00

132 lines
3.0 KiB
Go

//go:build !remote
package libpod
import (
"bufio"
"errors"
"fmt"
"os/exec"
"strings"
"sync"
"github.com/containers/podman/v6/libpod/define"
"github.com/containers/podman/v6/pkg/util"
"github.com/google/shlex"
"github.com/sirupsen/logrus"
)
var isDescriptor = map[string]bool{}
func init() {
allDescriptors, err := util.GetContainerPidInformationDescriptors()
if err != nil {
// Should never happen
logrus.Debugf("failed call to util.GetContainerPidInformationDescriptors()")
return
}
for _, d := range allDescriptors {
isDescriptor[d] = true
}
}
// Top gathers statistics about the running processes in a container. It returns a
// []string for output
func (c *Container) Top(descriptors []string) ([]string, error) {
conStat, err := c.State()
if err != nil {
return nil, fmt.Errorf("unable to look up state for %s: %w", c.ID(), err)
}
if conStat != define.ContainerStateRunning {
return nil, errors.New("top can only be used on running containers")
}
// Default to 'ps -ef' compatible descriptors
if len(strings.Join(descriptors, "")) == 0 {
descriptors = []string{"user", "pid", "ppid", "pcpu", "etime", "tty", "time", "args"}
}
// If everything in descriptors is a supported AIX format
// descriptor, we use 'ps -ao <descriptors>', otherwise we pass
// everything straight through to ps.
supportedDescriptors := true
for _, d := range descriptors {
if _, ok := isDescriptor[d]; !ok {
supportedDescriptors = false
break
}
}
if supportedDescriptors {
descriptors = []string{"-o", strings.Join(descriptors, ",")}
}
// Note that the descriptors to ps(1) must be shlexed (see #12452).
psDescriptors := []string{}
for _, d := range descriptors {
shSplit, err := shlex.Split(d)
if err != nil {
return nil, fmt.Errorf("parsing ps args: %w", err)
}
for _, s := range shSplit {
if s != "" {
psDescriptors = append(psDescriptors, s)
}
}
}
jailName, err := c.jailName()
if err != nil {
return nil, fmt.Errorf("getting jail name: %w", err)
}
args := append([]string{"-J", jailName}, psDescriptors...)
output, err := execPS(args)
if err != nil {
return nil, fmt.Errorf("executing ps(1): %w", err)
}
return output, nil
}
func execPS(args []string) ([]string, error) {
cmd := exec.Command("ps", args...)
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
stderrPipe, err := cmd.StderrPipe()
if err != nil {
return nil, err
}
var wg sync.WaitGroup
wg.Add(2)
stdout := []string{}
go func() {
scanner := bufio.NewScanner(stdoutPipe)
for scanner.Scan() {
stdout = append(stdout, scanner.Text())
}
wg.Done()
}()
stderr := []string{}
go func() {
scanner := bufio.NewScanner(stderrPipe)
for scanner.Scan() {
stderr = append(stderr, scanner.Text())
}
wg.Done()
}()
if err := cmd.Start(); err != nil {
return nil, err
}
wg.Wait()
if err := cmd.Wait(); err != nil {
return nil, fmt.Errorf("ps(1) command failed: %w, output: %s", err, strings.Join(stderr, " "))
}
return stdout, nil
}