diff --git a/process/process.go b/process/process.go index 59441a05..482537d5 100644 --- a/process/process.go +++ b/process/process.go @@ -27,6 +27,7 @@ type Process struct { numCtxSwitches *NumCtxSwitchesStat uids []int32 gids []int32 + groups []int32 numThreads int32 memInfo *MemoryInfoStat sigInfo *SignalInfoStat @@ -312,3 +313,8 @@ func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) { return 100 * cput.Total() / totalTime, nil } + +// Groups returns all group IDs(include supplementary groups) of the process as a slice of the int +func (p *Process) Groups() ([]int32, error) { + return p.GroupsWithContext(context.Background()) +} diff --git a/process/process_darwin.go b/process/process_darwin.go index 3eb53e68..c5ec0c6f 100644 --- a/process/process_darwin.go +++ b/process/process_darwin.go @@ -267,6 +267,20 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return gids, nil } + +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + k, err := p.getKProc() + if err != nil { + return nil, err + } + + groups := make([]int32, k.Eproc.Ucred.Ngroups) + for i := int16(0); i < k.Eproc.Ucred.Ngroups; i++ { + groups[i] = int32(k.Eproc.Ucred.Groups[i]) + } + + return groups, nil +} func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } diff --git a/process/process_fallback.go b/process/process_fallback.go index 1cb55c8b..43803e78 100644 --- a/process/process_fallback.go +++ b/process/process_fallback.go @@ -139,6 +139,10 @@ func (p *Process) Gids() ([]int32, error) { func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return []int32{}, common.ErrNotImplementedError } + +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + return []int32{}, common.ErrNotImplementedError +} func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } diff --git a/process/process_freebsd.go b/process/process_freebsd.go index 0cf1699d..84dbead9 100644 --- a/process/process_freebsd.go +++ b/process/process_freebsd.go @@ -230,6 +230,20 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return gids, nil } + +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + k, err := p.getKProc() + if err != nil { + return nil, err + } + + groups := make([]int32, k.Ngroups) + for i := int16(0); i < k.Ngroups; i++ { + groups[i] = int32(k.Groups[i]) + } + + return groups, nil +} func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } diff --git a/process/process_linux.go b/process/process_linux.go index f0e1a4dd..6a509099 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -228,6 +228,14 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return p.gids, nil } +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + err := p.fillFromStatusWithContext(ctx) + if err != nil { + return []int32{}, err + } + return p.groups, nil +} + // Terminal returns a terminal which is associated with the process. func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) @@ -1015,6 +1023,16 @@ func (p *Process) fillFromStatusWithContext(ctx context.Context) error { } p.gids = append(p.gids, int32(v)) } + case "Groups": + groups := strings.Fields(value) + p.groups = make([]int32, 0, len(groups)) + for _, i := range groups { + v, err := strconv.ParseInt(i, 10, 32) + if err != nil { + return err + } + p.groups = append(p.groups, int32(v)) + } case "Threads": v, err := strconv.ParseInt(value, 10, 32) if err != nil { diff --git a/process/process_openbsd.go b/process/process_openbsd.go index 1f3c645b..93f9875e 100644 --- a/process/process_openbsd.go +++ b/process/process_openbsd.go @@ -221,6 +221,14 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return gids, nil } +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + k, err := p.getKProc() + if err != nil { + return nil, err + } + + return k.Groups, nil +} func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } diff --git a/process/process_test.go b/process/process_test.go index 59404671..60b134cc 100644 --- a/process/process_test.go +++ b/process/process_test.go @@ -244,6 +244,20 @@ func Test_Process_Nice(t *testing.T) { t.Errorf("invalid nice: %d", n) } } + +func Test_Process_Groups(t *testing.T) { + p := testGetProcess() + + v, err := p.Groups() + skipIfNotImplementedErr(t, err) + if err != nil { + t.Errorf("getting groups error %v", err) + } + if len(v) <= 0 || v[0] < 0 { + t.Errorf("invalid Groups: %v", v) + } +} + func Test_Process_NumThread(t *testing.T) { p := testGetProcess() diff --git a/process/process_windows.go b/process/process_windows.go index d42e2aab..efb4dc1e 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -409,6 +409,11 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { var gids []int32 return gids, common.ErrNotImplementedError } + +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + var groups []int32 + return groups, common.ErrNotImplementedError +} func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) }