diff --git a/providers/darwin/process_darwin_amd64.go b/providers/darwin/process_darwin_amd64.go index ad1864df..a2122038 100644 --- a/providers/darwin/process_darwin_amd64.go +++ b/providers/darwin/process_darwin_amd64.go @@ -85,6 +85,7 @@ func (s darwinSystem) Self() (types.Process, error) { } type process struct { + info *types.ProcessInfo pid int cwd string exe string @@ -96,7 +97,20 @@ func (p *process) PID() int { return p.pid } +func (p *process) Parent() (types.Process, error) { + info, err := p.Info() + if err != nil { + return nil, err + } + + return &process{pid: info.PPID}, nil +} + func (p *process) Info() (types.ProcessInfo, error) { + if p.info != nil { + return *p.info, nil + } + var task procTaskAllInfo if err := getProcTaskAllInfo(p.pid, &task); err != nil { return types.ProcessInfo{}, err @@ -111,7 +125,7 @@ func (p *process) Info() (types.ProcessInfo, error) { return types.ProcessInfo{}, err } - return types.ProcessInfo{ + p.info = &types.ProcessInfo{ Name: int8SliceToString(task.Pbsd.Pbi_name[:]), PID: p.pid, PPID: int(task.Pbsd.Pbi_ppid), @@ -120,7 +134,9 @@ func (p *process) Info() (types.ProcessInfo, error) { Args: p.args, StartTime: time.Unix(int64(task.Pbsd.Pbi_start_tvsec), int64(task.Pbsd.Pbi_start_tvusec)*int64(time.Microsecond)), - }, nil + } + + return *p.info, nil } func (p *process) User() (types.UserInfo, error) { diff --git a/providers/linux/os_test.go b/providers/linux/os_test.go index 1df5e131..2977887e 100644 --- a/providers/linux/os_test.go +++ b/providers/linux/os_test.go @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +// +build !windows + package linux import ( diff --git a/providers/linux/process_linux.go b/providers/linux/process_linux.go index 4f5425e8..6111a36a 100644 --- a/providers/linux/process_linux.go +++ b/providers/linux/process_linux.go @@ -73,6 +73,20 @@ func (p *process) PID() int { return p.Proc.PID } +func (p *process) Parent() (types.Process, error) { + info, err := p.Info() + if err != nil { + return nil, err + } + + proc, err := p.fs.NewProc(info.PPID) + if err != nil { + return nil, err + } + + return &process{Proc: proc, fs: p.fs}, nil +} + func (p *process) path(pa ...string) string { return p.fs.Path(append([]string{strconv.Itoa(p.PID())}, pa...)...) } diff --git a/providers/windows/process_windows.go b/providers/windows/process_windows.go index 8a19e43e..6ff7da53 100644 --- a/providers/windows/process_windows.go +++ b/providers/windows/process_windows.go @@ -79,6 +79,15 @@ func (p *process) PID() int { return p.pid } +func (p *process) Parent() (types.Process, error) { + info, err := p.Info() + if err != nil { + return nil, err + } + + return newProcess(info.PPID) +} + func newProcess(pid int) (*process, error) { p := &process{pid: pid} if err := p.init(); err != nil { diff --git a/system_test.go b/system_test.go index 79e1a573..0f817f16 100644 --- a/system_test.go +++ b/system_test.go @@ -115,6 +115,7 @@ func TestSelf(t *testing.T) { assert.EqualValues(t, os.Getpid(), info.PID) assert.EqualValues(t, os.Getppid(), info.PPID) assert.Equal(t, os.Args, info.Args) + assert.WithinDuration(t, info.StartTime, time.Now(), 10*time.Second) wd, err := os.Getwd() if err != nil { @@ -128,10 +129,11 @@ func TestSelf(t *testing.T) { } assert.Equal(t, exe, info.Exe) + parent, err := process.Parent() if err != nil { t.Fatal(err) } - assert.WithinDuration(t, info.StartTime, time.Now(), 10*time.Second) + assert.EqualValues(t, os.Getppid(), parent.PID()) user, err := process.User() if err != nil { diff --git a/types/process.go b/types/process.go index ade433f8..8dd2074c 100644 --- a/types/process.go +++ b/types/process.go @@ -24,6 +24,7 @@ type Process interface { Info() (ProcessInfo, error) Memory() (MemoryInfo, error) User() (UserInfo, error) + Parent() (Process, error) PID() int }