Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions pkg/sentry/control/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,9 @@ type Process struct {
UID auth.KUID `json:"uid"`
PID kernel.ThreadID `json:"pid"`
// Parent PID
PPID kernel.ThreadID `json:"ppid"`
PPID kernel.ThreadID `json:"ppid"`
// Process Group ID
PGID kernel.ThreadID `json:"pgid"`
Threads []kernel.ThreadID `json:"threads"`
// Processor utilization
C int32 `json:"c"`
Expand All @@ -382,17 +384,18 @@ type Process struct {
}

// ProcessListToTable prints a table with the following format:
// UID PID PPID C TTY STIME TIME CMD
// 0 1 0 0 pty/4 14:04 505262ns tail
// UID PID PPID PGID C TTY STIME TIME CMD
// 0 1 0 1 0 pty/4 14:04 505262ns tail
func ProcessListToTable(pl []*Process) string {
var buf bytes.Buffer
tw := tabwriter.NewWriter(&buf, 10, 1, 3, ' ', 0)
fmt.Fprint(tw, "UID\tPID\tPPID\tC\tTTY\tSTIME\tTIME\tCMD")
fmt.Fprint(tw, "UID\tPID\tPPID\tPGID\tC\tTTY\tSTIME\tTIME\tCMD")
for _, d := range pl {
fmt.Fprintf(tw, "\n%d\t%d\t%d\t%d\t%s\t%s\t%s\t%s",
fmt.Fprintf(tw, "\n%d\t%d\t%d\t%d\t%d\t%s\t%s\t%s\t%s",
d.UID,
d.PID,
d.PPID,
d.PGID,
d.C,
d.TTY,
d.STime,
Expand Down Expand Up @@ -447,11 +450,16 @@ func Processes(k *kernel.Kernel, containerID string, out *[]*Process) error {
if p := tg.Leader().Parent(); p != nil {
ppid = pidns.IDOfThreadGroup(p.ThreadGroup())
}
pgid := kernel.ThreadID(0)
if pg := tg.ProcessGroup(); pg != nil {
pgid = kernel.ThreadID(pidns.IDOfProcessGroup(pg))
}
threads := tg.MemberIDs(pidns)
*out = append(*out, &Process{
UID: tg.Leader().Credentials().EffectiveKUID,
PID: pid,
PPID: ppid,
PGID: pgid,
Threads: threads,
STime: formatStartTime(now, tg.Leader().StartTime()),
C: percentCPU(tg.CPUStats(), tg.Leader().StartTime(), now),
Expand Down
10 changes: 6 additions & 4 deletions pkg/sentry/control/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ func TestProcessListTable(t *testing.T) {
}{
{
pl: []*Process{},
expected: "UID PID PPID C TTY STIME TIME CMD",
expected: "UID PID PPID PGID C TTY STIME TIME CMD",
},
{
pl: []*Process{
{
UID: 0,
PID: 0,
PPID: 0,
PGID: 0,
C: 0,
TTY: "?",
STime: "0",
Expand All @@ -52,16 +53,17 @@ func TestProcessListTable(t *testing.T) {
UID: 1,
PID: 1,
PPID: 1,
PGID: 1,
C: 1,
TTY: "pts/4",
STime: "1",
Time: "1",
Cmd: "one",
},
},
expected: `UID PID PPID C TTY STIME TIME CMD
0 0 0 0 ? 0 0 zero
1 1 1 1 pts/4 1 1 one`,
expected: `UID PID PPID PGID C TTY STIME TIME CMD
0 0 0 0 0 ? 0 0 zero
1 1 1 1 1 pts/4 1 1 one`,
},
}

Expand Down
44 changes: 44 additions & 0 deletions runsc/container/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ func procEqual(got, want *control.Process) bool {
if want.PPID != -1 && want.PPID != got.PPID {
return false
}
if want.PGID != -1 && want.PGID != got.PGID {
return false
}
if len(want.TTY) != 0 && want.TTY != got.TTY {
return false
}
Expand All @@ -269,6 +272,7 @@ func newProcessBuilder() *processBuilder {
UID: math.MaxUint32,
PID: -1,
PPID: -1,
PGID: -1,
},
}
}
Expand All @@ -288,6 +292,11 @@ func (p *processBuilder) PPID(ppid kernel.ThreadID) *processBuilder {
return p
}

func (p *processBuilder) PGID(pgid kernel.ThreadID) *processBuilder {
p.process.PGID = pgid
return p
}

func (p *processBuilder) UID(uid auth.KUID) *processBuilder {
p.process.UID = uid
return p
Expand Down Expand Up @@ -2593,6 +2602,41 @@ func TestTTYField(t *testing.T) {
}
}

// TestPGIDField checks PGID returned by container.Processes().
func TestPGIDField(t *testing.T) {
stop := testutil.StartReaper()
defer stop()

conf := testutil.TestConfig(t)
spec := testutil.NewSpecWithArgs("/bin/sleep", "10000")
_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
defer cleanup()

args := Args{
ID: testutil.RandomContainerID(),
Spec: spec,
BundleDir: bundleDir,
}
c, err := New(conf, args)
if err != nil {
t.Fatalf("error creating container: %v", err)
}
defer c.Destroy()
if err := c.Start(conf); err != nil {
t.Fatalf("error starting container: %v", err)
}

expectedPL := []*control.Process{
newProcessBuilder().PID(1).PPID(0).PGID(1).Cmd("sleep").Process(),
}
if err := waitForProcessList(c, expectedPL); err != nil {
t.Fatalf("error waiting for process list with pgid: %v", err)
}
}

// Test that container can run even when there are corrupt state files in the
// root directiry.
func TestCreateWithCorruptedStateFile(t *testing.T) {
Expand Down
Loading