vendor latest containers/psgo

Signed-off-by: Valentin Rothberg <vrothberg@suse.com>

Closes: #1162
Approved by: rhatdan
This commit is contained in:
Valentin Rothberg
2018-07-26 15:26:52 +02:00
committed by Atomic Bot
parent d9ae17400d
commit 159f7f179b
16 changed files with 979 additions and 636 deletions

View File

@ -0,0 +1,205 @@
package process
import (
"os"
"strconv"
"time"
"github.com/containers/psgo/internal/host"
"github.com/containers/psgo/internal/proc"
"github.com/opencontainers/runc/libcontainer/user"
"github.com/pkg/errors"
)
// Process includes process-related from the /proc FS.
type Process struct {
// PID is the process ID.
Pid string
// Stat contains data from /proc/$pid/stat.
Stat proc.Stat
// Status containes data from /proc/$pid/status.
Status proc.Status
// CmdLine containes data from /proc/$pid/cmdline.
CmdLine []string
// Label containers data from /proc/$pid/attr/current.
Label string
// PidNS contains data from /proc/$pid/ns/pid.
PidNS string
// Huser is the effective host user of a container process.
Huser string
// Hgroup is the effective host group of a container process.
Hgroup string
}
// LookupGID returns the textual group ID, if it can be optained, or the
// decimal representation otherwise.
func LookupGID(gid string) (string, error) {
gidNum, err := strconv.Atoi(gid)
if err != nil {
return "", errors.Wrap(err, "error parsing group ID")
}
g, err := user.LookupGid(gidNum)
if err != nil {
return gid, nil
}
return g.Name, nil
}
// LookupUID return the textual user ID, if it can be optained, or the decimal
// representation otherwise.
func LookupUID(uid string) (string, error) {
uidNum, err := strconv.Atoi(uid)
if err != nil {
return "", errors.Wrap(err, "error parsing user ID")
}
u, err := user.LookupUid(uidNum)
if err != nil {
return uid, nil
}
return u.Name, nil
}
// New returns a new Process with the specified pid and parses the relevant
// data from /proc and /dev.
func New(pid string) (*Process, error) {
p := Process{Pid: pid}
if err := p.parseStat(); err != nil {
return nil, err
}
if err := p.parseStatus(); err != nil {
return nil, err
}
if err := p.parseCmdLine(); err != nil {
return nil, err
}
if err := p.parsePIDNamespace(); err != nil {
// Ignore permission errors as those occur for some pids when
// the caller has limited permissions.
if !os.IsPermission(err) {
return nil, err
}
}
if err := p.parseLabel(); err != nil {
return nil, err
}
return &p, nil
}
// FromPIDs creates a new Process for each pid.
func FromPIDs(pids []string) ([]*Process, error) {
processes := []*Process{}
for _, pid := range pids {
p, err := New(pid)
if err != nil {
if os.IsNotExist(err) {
// proc parsing is racy
// Let's ignore "does not exist" errors
continue
}
return nil, err
}
processes = append(processes, p)
}
return processes, nil
}
// parseStat parses /proc/$pid/stat.
func (p *Process) parseStat() error {
s, err := proc.ParseStat(p.Pid)
if err != nil {
return err
}
p.Stat = *s
return nil
}
// parseStatus parses /proc/$pid/status.
func (p *Process) parseStatus() error {
s, err := proc.ParseStatus(p.Pid)
if err != nil {
return err
}
p.Status = *s
return nil
}
// parseCmdLine parses /proc/$pid/cmdline.
func (p *Process) parseCmdLine() error {
s, err := proc.ParseCmdLine(p.Pid)
if err != nil {
return err
}
p.CmdLine = s
return nil
}
// parsePIDNamespace parses all host-related data fields.
func (p *Process) parsePIDNamespace() error {
pidNS, err := proc.ParsePIDNamespace(p.Pid)
if err != nil {
return err
}
p.PidNS = pidNS
return nil
}
// parseLabel parses the security label.
func (p *Process) parseLabel() error {
label, err := proc.ParseAttrCurrent(p.Pid)
if err != nil {
return err
}
p.Label = label
return nil
}
// SetHostData sets all host-related data fields.
func (p *Process) SetHostData() error {
var err error
p.Huser, err = LookupUID(p.Status.Uids[1])
if err != nil {
return err
}
p.Hgroup, err = LookupGID(p.Status.Gids[1])
if err != nil {
return err
}
return nil
}
// ElapsedTime returns the time.Duration since process p was created.
func (p *Process) ElapsedTime() (time.Duration, error) {
sinceBoot, err := strconv.ParseInt(p.Stat.Starttime, 10, 64)
if err != nil {
return 0, err
}
sinceBoot = sinceBoot / host.ClockTicks()
bootTime, err := host.BootTime()
if err != nil {
return 0, err
}
created := time.Unix(sinceBoot+bootTime, 0)
return (time.Now()).Sub(created), nil
}
// CPUTime returns the cumlative CPU time of process p as a time.Duration.
func (p *Process) CPUTime() (time.Duration, error) {
user, err := strconv.ParseInt(p.Stat.Utime, 10, 64)
if err != nil {
return 0, err
}
system, err := strconv.ParseInt(p.Stat.Stime, 10, 64)
if err != nil {
return 0, err
}
secs := (user + system) / host.ClockTicks()
cpu := time.Unix(secs, 0)
return cpu.Sub(time.Unix(0, 0)), nil
}