vendor psgo v1.2

The psgo library now be used concurrently by multiple goroutines without
interferring with another.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2019-03-11 18:05:37 +01:00
parent 6421208e0f
commit 508ab7f565
6 changed files with 83 additions and 107 deletions

View File

@ -20,7 +20,7 @@ github.com/vbauerster/mpb v3.3.4
github.com/mattn/go-isatty v0.0.4 github.com/mattn/go-isatty v0.0.4
github.com/VividCortex/ewma v1.1.1 github.com/VividCortex/ewma v1.1.1
github.com/containers/storage v1.10 github.com/containers/storage v1.10
github.com/containers/psgo v1.1 github.com/containers/psgo v1.2
github.com/coreos/go-systemd v14 github.com/coreos/go-systemd v14
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
github.com/cyphar/filepath-securejoin v0.2.1 github.com/cyphar/filepath-securejoin v0.2.1

View File

@ -31,12 +31,9 @@ type TTY struct {
Path string Path string
} }
// cache TTYs to avoid redundant lookups
var devices *[]TTY
// FindTTY return the corresponding TTY to the ttyNr or nil of non could be // FindTTY return the corresponding TTY to the ttyNr or nil of non could be
// found. // found.
func FindTTY(ttyNr uint64) (*TTY, error) { func FindTTY(ttyNr uint64, devices *[]TTY) (*TTY, error) {
// (man 5 proc) The minor device number is contained in the combination // (man 5 proc) The minor device number is contained in the combination
// of bits 31 to 20 and 7 to 0; the major device number is in bits 15 // of bits 31 to 20 and 7 to 0; the major device number is in bits 15
// to 8. // to 8.
@ -44,7 +41,7 @@ func FindTTY(ttyNr uint64) (*TTY, error) {
min := (ttyNr & 0xFF) | ((ttyNr >> 20) & 0xFFF) min := (ttyNr & 0xFF) | ((ttyNr >> 20) & 0xFFF)
if devices == nil { if devices == nil {
devs, err := getTTYs() devs, err := TTYs()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -70,8 +67,8 @@ func minDevNum(rdev uint64) uint64 {
return (rdev & 0xff) | ((rdev >> 12) & 0xfff00) return (rdev & 0xff) | ((rdev >> 12) & 0xfff00)
} }
// getTTYs parses /dev for tty and pts devices. // TTYs parses /dev for tty and pts devices.
func getTTYs() (*[]TTY, error) { func TTYs() (*[]TTY, error) {
devDir, err := os.Open("/dev/") devDir, err := os.Open("/dev/")
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -21,7 +21,6 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/containers/psgo/internal/types"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -207,11 +206,11 @@ func readStatusDefault(pid string) ([]string, error) {
} }
// ParseStatus parses the /proc/$pid/status file and returns a *Status. // ParseStatus parses the /proc/$pid/status file and returns a *Status.
func ParseStatus(ctx *types.PsContext, pid string) (*Status, error) { func ParseStatus(pid string, joinUserNS bool) (*Status, error) {
var lines []string var lines []string
var err error var err error
if ctx.JoinUserNS { if joinUserNS {
lines, err = readStatusUserNS(pid) lines, err = readStatusUserNS(pid)
} else { } else {
lines, err = readStatusDefault(pid) lines, err = readStatusDefault(pid)

View File

@ -21,7 +21,6 @@ import (
"github.com/containers/psgo/internal/host" "github.com/containers/psgo/internal/host"
"github.com/containers/psgo/internal/proc" "github.com/containers/psgo/internal/proc"
"github.com/containers/psgo/internal/types"
"github.com/opencontainers/runc/libcontainer/user" "github.com/opencontainers/runc/libcontainer/user"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -76,13 +75,13 @@ func LookupUID(uid string) (string, error) {
// New returns a new Process with the specified pid and parses the relevant // New returns a new Process with the specified pid and parses the relevant
// data from /proc and /dev. // data from /proc and /dev.
func New(ctx *types.PsContext, pid string) (*Process, error) { func New(pid string, joinUserNS bool) (*Process, error) {
p := Process{Pid: pid} p := Process{Pid: pid}
if err := p.parseStat(); err != nil { if err := p.parseStat(); err != nil {
return nil, err return nil, err
} }
if err := p.parseStatus(ctx); err != nil { if err := p.parseStatus(joinUserNS); err != nil {
return nil, err return nil, err
} }
if err := p.parseCmdLine(); err != nil { if err := p.parseCmdLine(); err != nil {
@ -103,10 +102,10 @@ func New(ctx *types.PsContext, pid string) (*Process, error) {
} }
// FromPIDs creates a new Process for each pid. // FromPIDs creates a new Process for each pid.
func FromPIDs(ctx *types.PsContext, pids []string) ([]*Process, error) { func FromPIDs(pids []string, joinUserNS bool) ([]*Process, error) {
processes := []*Process{} processes := []*Process{}
for _, pid := range pids { for _, pid := range pids {
p, err := New(ctx, pid) p, err := New(pid, joinUserNS)
if err != nil { if err != nil {
if os.IsNotExist(errors.Cause(err)) { if os.IsNotExist(errors.Cause(err)) {
// proc parsing is racy // proc parsing is racy
@ -131,8 +130,8 @@ func (p *Process) parseStat() error {
} }
// parseStatus parses /proc/$pid/status. // parseStatus parses /proc/$pid/status.
func (p *Process) parseStatus(ctx *types.PsContext) error { func (p *Process) parseStatus(joinUserNS bool) error {
s, err := proc.ParseStatus(ctx, p.Pid) s, err := proc.ParseStatus(p.Pid, joinUserNS)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,22 +0,0 @@
// Copyright 2018 psgo authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package types
// PsContext controls some internals of the psgo library.
type PsContext struct {
// JoinUserNS will force /proc and /dev parsing from within each PIDs
// user namespace.
JoinUserNS bool
}

View File

@ -39,14 +39,22 @@ import (
"github.com/containers/psgo/internal/dev" "github.com/containers/psgo/internal/dev"
"github.com/containers/psgo/internal/proc" "github.com/containers/psgo/internal/proc"
"github.com/containers/psgo/internal/process" "github.com/containers/psgo/internal/process"
"github.com/containers/psgo/internal/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
type psContext struct {
// Processes in the container.
containersProcesses []*process.Process
// Processes on the host. Used to map those to the ones running in the container.
hostProcesses []*process.Process
// tty and pty devices.
ttys *[]dev.TTY
}
// processFunc is used to map a given aixFormatDescriptor to a corresponding // processFunc is used to map a given aixFormatDescriptor to a corresponding
// function extracting the desired data from a process. // function extracting the desired data from a process.
type processFunc func(*process.Process) (string, error) type processFunc func(*process.Process, *psContext) (string, error)
// aixFormatDescriptor as mentioned in the ps(1) manpage. A given descriptor // aixFormatDescriptor as mentioned in the ps(1) manpage. A given descriptor
// can either be specified via its code (e.g., "%C") or its normal representation // can either be specified via its code (e.g., "%C") or its normal representation
@ -99,13 +107,6 @@ var (
// ErrUnkownDescriptor is returned when an unknown descriptor is parsed. // ErrUnkownDescriptor is returned when an unknown descriptor is parsed.
ErrUnkownDescriptor = errors.New("unknown descriptor") ErrUnkownDescriptor = errors.New("unknown descriptor")
// hostProcesses are the processes on the host. It should only be used
// in the context of containers and is meant to display data of the
// container processes from the host's (i.e., calling process) view.
// Currently, all host processes contain only the required data from
// /proc/$pid/status.
hostProcesses []*process.Process
aixFormatDescriptors = []aixFormatDescriptor{ aixFormatDescriptors = []aixFormatDescriptor{
{ {
code: "%C", code: "%C",
@ -282,11 +283,16 @@ func JoinNamespaceAndProcessInfo(pid string, descriptors []string) ([][]string,
return nil, err return nil, err
} }
ctx := new(psContext)
// extract data from host processes only on-demand / when at least one // extract data from host processes only on-demand / when at least one
// of the specified descriptors requires host data // of the specified descriptors requires host data
for _, d := range aixDescriptors { for _, d := range aixDescriptors {
if d.onHost { if d.onHost {
setHostProcesses(pid) ctx.hostProcesses, err = hostProcesses(pid)
if err != nil {
return nil, err
}
break break
} }
} }
@ -330,18 +336,17 @@ func JoinNamespaceAndProcessInfo(pid string, descriptors []string) ([][]string,
return return
} }
ctx := types.PsContext{
// join the user NS if the pid's user NS is different // join the user NS if the pid's user NS is different
// to the caller's user NS. // to the caller's user NS.
JoinUserNS: currentUserNs != pidUserNs, joinUserNS := currentUserNs != pidUserNs
}
processes, err := process.FromPIDs(&ctx, pids) ctx.containersProcesses, err = process.FromPIDs(pids, joinUserNS)
if err != nil { if err != nil {
dataErr = err dataErr = err
return return
} }
data, dataErr = processDescriptors(aixDescriptors, processes) data, dataErr = processDescriptors(aixDescriptors, ctx)
}() }()
wg.Wait() wg.Wait()
@ -417,43 +422,41 @@ func ProcessInfoByPids(pids []string, descriptors []string) ([][]string, error)
return nil, err return nil, err
} }
ctx := types.PsContext{JoinUserNS: false} ctx := new(psContext)
processes, err := process.FromPIDs(&ctx, pids) ctx.containersProcesses, err = process.FromPIDs(pids, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return processDescriptors(aixDescriptors, processes) return processDescriptors(aixDescriptors, ctx)
} }
// setHostProcesses sets `hostProcesses`. // hostProcesses returns all processes running in the current namespace.
func setHostProcesses(pid string) error { func hostProcesses(pid string) ([]*process.Process, error) {
// get processes // get processes
pids, err := proc.GetPIDsFromCgroup(pid) pids, err := proc.GetPIDsFromCgroup(pid)
if err != nil { if err != nil {
return err return nil, err
} }
ctx := types.PsContext{JoinUserNS: false} processes, err := process.FromPIDs(pids, false)
processes, err := process.FromPIDs(&ctx, pids)
if err != nil { if err != nil {
return err return nil, err
} }
// set the additional host data // set the additional host data
for _, p := range processes { for _, p := range processes {
if err := p.SetHostData(); err != nil { if err := p.SetHostData(); err != nil {
return err return nil, err
} }
} }
hostProcesses = processes return processes, nil
return nil
} }
// processDescriptors calls each `procFn` of all formatDescriptors on each // processDescriptors calls each `procFn` of all formatDescriptors on each
// process and returns an array of tab-separated strings. // process and returns an array of tab-separated strings.
func processDescriptors(formatDescriptors []aixFormatDescriptor, processes []*process.Process) ([][]string, error) { func processDescriptors(formatDescriptors []aixFormatDescriptor, ctx *psContext) ([][]string, error) {
data := [][]string{} data := [][]string{}
// create header // create header
header := []string{} header := []string{}
@ -463,10 +466,10 @@ func processDescriptors(formatDescriptors []aixFormatDescriptor, processes []*pr
data = append(data, header) data = append(data, header)
// dispatch all descriptor functions on each process // dispatch all descriptor functions on each process
for _, proc := range processes { for _, proc := range ctx.containersProcesses {
pData := []string{} pData := []string{}
for _, desc := range formatDescriptors { for _, desc := range formatDescriptors {
dataStr, err := desc.procFn(proc) dataStr, err := desc.procFn(proc, ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -480,8 +483,8 @@ func processDescriptors(formatDescriptors []aixFormatDescriptor, processes []*pr
// findHostProcess returns the corresponding process from `hostProcesses` or // findHostProcess returns the corresponding process from `hostProcesses` or
// nil if non is found. // nil if non is found.
func findHostProcess(p *process.Process) *process.Process { func findHostProcess(p *process.Process, ctx *psContext) *process.Process {
for _, hp := range hostProcesses { for _, hp := range ctx.hostProcesses {
// We expect the host process to be in another namespace, so // We expect the host process to be in another namespace, so
// /proc/$pid/status.NSpid must have at least two entries. // /proc/$pid/status.NSpid must have at least two entries.
if len(hp.Status.NSpid) < 2 { if len(hp.Status.NSpid) < 2 {
@ -499,78 +502,78 @@ func findHostProcess(p *process.Process) *process.Process {
// processGROUP returns the effective group ID of the process. This will be // processGROUP returns the effective group ID of the process. This will be
// the textual group ID, if it can be optained, or a decimal representation // the textual group ID, if it can be optained, or a decimal representation
// otherwise. // otherwise.
func processGROUP(p *process.Process) (string, error) { func processGROUP(p *process.Process, ctx *psContext) (string, error) {
return process.LookupGID(p.Status.Gids[1]) return process.LookupGID(p.Status.Gids[1])
} }
// processRGROUP returns the real group ID of the process. This will be // processRGROUP returns the real group ID of the process. This will be
// the textual group ID, if it can be optained, or a decimal representation // the textual group ID, if it can be optained, or a decimal representation
// otherwise. // otherwise.
func processRGROUP(p *process.Process) (string, error) { func processRGROUP(p *process.Process, ctx *psContext) (string, error) {
return process.LookupGID(p.Status.Gids[0]) return process.LookupGID(p.Status.Gids[0])
} }
// processPPID returns the parent process ID of process p. // processPPID returns the parent process ID of process p.
func processPPID(p *process.Process) (string, error) { func processPPID(p *process.Process, ctx *psContext) (string, error) {
return p.Status.PPid, nil return p.Status.PPid, nil
} }
// processUSER returns the effective user name of the process. This will be // processUSER returns the effective user name of the process. This will be
// the textual user ID, if it can be optained, or a decimal representation // the textual user ID, if it can be optained, or a decimal representation
// otherwise. // otherwise.
func processUSER(p *process.Process) (string, error) { func processUSER(p *process.Process, ctx *psContext) (string, error) {
return process.LookupUID(p.Status.Uids[1]) return process.LookupUID(p.Status.Uids[1])
} }
// processRUSER returns the effective user name of the process. This will be // processRUSER returns the effective user name of the process. This will be
// the textual user ID, if it can be optained, or a decimal representation // the textual user ID, if it can be optained, or a decimal representation
// otherwise. // otherwise.
func processRUSER(p *process.Process) (string, error) { func processRUSER(p *process.Process, ctx *psContext) (string, error) {
return process.LookupUID(p.Status.Uids[0]) return process.LookupUID(p.Status.Uids[0])
} }
// processName returns the name of process p in the format "[$name]". // processName returns the name of process p in the format "[$name]".
func processName(p *process.Process) (string, error) { func processName(p *process.Process, ctx *psContext) (string, error) {
return fmt.Sprintf("[%s]", p.Status.Name), nil return fmt.Sprintf("[%s]", p.Status.Name), nil
} }
// processARGS returns the command of p with all its arguments. // processARGS returns the command of p with all its arguments.
func processARGS(p *process.Process) (string, error) { func processARGS(p *process.Process, ctx *psContext) (string, error) {
// ps (1) returns "[$name]" if command/args are empty // ps (1) returns "[$name]" if command/args are empty
if p.CmdLine[0] == "" { if p.CmdLine[0] == "" {
return processName(p) return processName(p, ctx)
} }
return strings.Join(p.CmdLine, " "), nil return strings.Join(p.CmdLine, " "), nil
} }
// processCOMM returns the command name (i.e., executable name) of process p. // processCOMM returns the command name (i.e., executable name) of process p.
func processCOMM(p *process.Process) (string, error) { func processCOMM(p *process.Process, ctx *psContext) (string, error) {
// ps (1) returns "[$name]" if command/args are empty // ps (1) returns "[$name]" if command/args are empty
if p.CmdLine[0] == "" { if p.CmdLine[0] == "" {
return processName(p) return processName(p, ctx)
} }
spl := strings.Split(p.CmdLine[0], "/") spl := strings.Split(p.CmdLine[0], "/")
return spl[len(spl)-1], nil return spl[len(spl)-1], nil
} }
// processNICE returns the nice value of process p. // processNICE returns the nice value of process p.
func processNICE(p *process.Process) (string, error) { func processNICE(p *process.Process, ctx *psContext) (string, error) {
return p.Stat.Nice, nil return p.Stat.Nice, nil
} }
// processPID returns the process ID of process p. // processPID returns the process ID of process p.
func processPID(p *process.Process) (string, error) { func processPID(p *process.Process, ctx *psContext) (string, error) {
return p.Pid, nil return p.Pid, nil
} }
// processPGID returns the process group ID of process p. // processPGID returns the process group ID of process p.
func processPGID(p *process.Process) (string, error) { func processPGID(p *process.Process, ctx *psContext) (string, error) {
return p.Stat.Pgrp, nil return p.Stat.Pgrp, nil
} }
// processPCPU returns how many percent of the CPU time process p uses as // processPCPU returns how many percent of the CPU time process p uses as
// a three digit float as string. // a three digit float as string.
func processPCPU(p *process.Process) (string, error) { func processPCPU(p *process.Process, ctx *psContext) (string, error) {
elapsed, err := p.ElapsedTime() elapsed, err := p.ElapsedTime()
if err != nil { if err != nil {
return "", err return "", err
@ -585,7 +588,7 @@ func processPCPU(p *process.Process) (string, error) {
} }
// processETIME returns the elapsed time since the process was started. // processETIME returns the elapsed time since the process was started.
func processETIME(p *process.Process) (string, error) { func processETIME(p *process.Process, ctx *psContext) (string, error) {
elapsed, err := p.ElapsedTime() elapsed, err := p.ElapsedTime()
if err != nil { if err != nil {
return "", nil return "", nil
@ -594,7 +597,7 @@ func processETIME(p *process.Process) (string, error) {
} }
// processTIME returns the cumulative CPU time of process p. // processTIME returns the cumulative CPU time of process p.
func processTIME(p *process.Process) (string, error) { func processTIME(p *process.Process, ctx *psContext) (string, error) {
cpu, err := p.CPUTime() cpu, err := p.CPUTime()
if err != nil { if err != nil {
return "", err return "", err
@ -603,13 +606,13 @@ func processTIME(p *process.Process) (string, error) {
} }
// processTTY returns the controlling tty (terminal) of process p. // processTTY returns the controlling tty (terminal) of process p.
func processTTY(p *process.Process) (string, error) { func processTTY(p *process.Process, ctx *psContext) (string, error) {
ttyNr, err := strconv.ParseUint(p.Stat.TtyNr, 10, 64) ttyNr, err := strconv.ParseUint(p.Stat.TtyNr, 10, 64)
if err != nil { if err != nil {
return "", nil return "", nil
} }
tty, err := dev.FindTTY(ttyNr) tty, err := dev.FindTTY(ttyNr, ctx.ttys)
if err != nil { if err != nil {
return "", nil return "", nil
} }
@ -623,7 +626,7 @@ func processTTY(p *process.Process) (string, error) {
// processVSZ returns the virtual memory size of process p in KiB (1024-byte // processVSZ returns the virtual memory size of process p in KiB (1024-byte
// units). // units).
func processVSZ(p *process.Process) (string, error) { func processVSZ(p *process.Process, ctx *psContext) (string, error) {
vmsize, err := strconv.Atoi(p.Stat.Vsize) vmsize, err := strconv.Atoi(p.Stat.Vsize)
if err != nil { if err != nil {
return "", err return "", err
@ -653,41 +656,41 @@ func parseCAP(cap string) (string, error) {
// processCAPAMB returns the set of ambient capabilties associated with // processCAPAMB returns the set of ambient capabilties associated with
// process p. If all capabilties are set, "full" is returned. If no // process p. If all capabilties are set, "full" is returned. If no
// capability is enabled, "none" is returned. // capability is enabled, "none" is returned.
func processCAPAMB(p *process.Process) (string, error) { func processCAPAMB(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapAmb) return parseCAP(p.Status.CapAmb)
} }
// processCAPINH returns the set of inheritable capabilties associated with // processCAPINH returns the set of inheritable capabilties associated with
// process p. If all capabilties are set, "full" is returned. If no // process p. If all capabilties are set, "full" is returned. If no
// capability is enabled, "none" is returned. // capability is enabled, "none" is returned.
func processCAPINH(p *process.Process) (string, error) { func processCAPINH(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapInh) return parseCAP(p.Status.CapInh)
} }
// processCAPPRM returns the set of permitted capabilties associated with // processCAPPRM returns the set of permitted capabilties associated with
// process p. If all capabilties are set, "full" is returned. If no // process p. If all capabilties are set, "full" is returned. If no
// capability is enabled, "none" is returned. // capability is enabled, "none" is returned.
func processCAPPRM(p *process.Process) (string, error) { func processCAPPRM(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapPrm) return parseCAP(p.Status.CapPrm)
} }
// processCAPEFF returns the set of effective capabilties associated with // processCAPEFF returns the set of effective capabilties associated with
// process p. If all capabilties are set, "full" is returned. If no // process p. If all capabilties are set, "full" is returned. If no
// capability is enabled, "none" is returned. // capability is enabled, "none" is returned.
func processCAPEFF(p *process.Process) (string, error) { func processCAPEFF(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapEff) return parseCAP(p.Status.CapEff)
} }
// processCAPBND returns the set of bounding capabilties associated with // processCAPBND returns the set of bounding capabilties associated with
// process p. If all capabilties are set, "full" is returned. If no // process p. If all capabilties are set, "full" is returned. If no
// capability is enabled, "none" is returned. // capability is enabled, "none" is returned.
func processCAPBND(p *process.Process) (string, error) { func processCAPBND(p *process.Process, ctx *psContext) (string, error) {
return parseCAP(p.Status.CapBnd) return parseCAP(p.Status.CapBnd)
} }
// processSECCOMP returns the seccomp mode of the process (i.e., disabled, // processSECCOMP returns the seccomp mode of the process (i.e., disabled,
// strict or filter) or "?" if /proc/$pid/status.seccomp has a unknown value. // strict or filter) or "?" if /proc/$pid/status.seccomp has a unknown value.
func processSECCOMP(p *process.Process) (string, error) { func processSECCOMP(p *process.Process, ctx *psContext) (string, error) {
switch p.Status.Seccomp { switch p.Status.Seccomp {
case "0": case "0":
return "disabled", nil return "disabled", nil
@ -702,14 +705,14 @@ func processSECCOMP(p *process.Process) (string, error) {
// processLABEL returns the process label of process p or "?" if the system // processLABEL returns the process label of process p or "?" if the system
// doesn't support labeling. // doesn't support labeling.
func processLABEL(p *process.Process) (string, error) { func processLABEL(p *process.Process, ctx *psContext) (string, error) {
return p.Label, nil return p.Label, nil
} }
// processHPID returns the PID of the corresponding host process of the // processHPID returns the PID of the corresponding host process of the
// (container) or "?" if no corresponding process could be found. // (container) or "?" if no corresponding process could be found.
func processHPID(p *process.Process) (string, error) { func processHPID(p *process.Process, ctx *psContext) (string, error) {
if hp := findHostProcess(p); hp != nil { if hp := findHostProcess(p, ctx); hp != nil {
return hp.Pid, nil return hp.Pid, nil
} }
return "?", nil return "?", nil
@ -717,8 +720,8 @@ func processHPID(p *process.Process) (string, error) {
// processHUSER returns the effective user ID of the corresponding host process // processHUSER returns the effective user ID of the corresponding host process
// of the (container) or "?" if no corresponding process could be found. // of the (container) or "?" if no corresponding process could be found.
func processHUSER(p *process.Process) (string, error) { func processHUSER(p *process.Process, ctx *psContext) (string, error) {
if hp := findHostProcess(p); hp != nil { if hp := findHostProcess(p, ctx); hp != nil {
return hp.Huser, nil return hp.Huser, nil
} }
return "?", nil return "?", nil
@ -727,14 +730,14 @@ func processHUSER(p *process.Process) (string, error) {
// processHGROUP returns the effective group ID of the corresponding host // processHGROUP returns the effective group ID of the corresponding host
// process of the (container) or "?" if no corresponding process could be // process of the (container) or "?" if no corresponding process could be
// found. // found.
func processHGROUP(p *process.Process) (string, error) { func processHGROUP(p *process.Process, ctx *psContext) (string, error) {
if hp := findHostProcess(p); hp != nil { if hp := findHostProcess(p, ctx); hp != nil {
return hp.Hgroup, nil return hp.Hgroup, nil
} }
return "?", nil return "?", nil
} }
// processState returns the process state of process p. // processState returns the process state of process p.
func processState(p *process.Process) (string, error) { func processState(p *process.Process, ctx *psContext) (string, error) {
return p.Status.State, nil return p.Status.State, nil
} }