From 878e0a701beedac5825aa8b191ce1ac9d5efc007 Mon Sep 17 00:00:00 2001 From: Lomanic Date: Thu, 8 Nov 2018 20:25:44 +0100 Subject: [PATCH] Fix #596 Implement process.Background and process.Foreground functions --- process/process.go | 13 +++++++++++++ process/process_darwin.go | 19 +++++++++++++++++++ process/process_fallback.go | 7 +++++++ process/process_freebsd.go | 20 ++++++++++++++++++++ process/process_linux.go | 22 ++++++++++++++++++++++ process/process_windows.go | 9 +++++++++ 6 files changed, 90 insertions(+) diff --git a/process/process.go b/process/process.go index a4b24f4..036ad91 100644 --- a/process/process.go +++ b/process/process.go @@ -146,6 +146,19 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { return false, err } +// Background returns true if the process is in background, false otherwise. +func (p *Process) Background() (bool, error) { + return p.BackgroundWithContext(context.Background()) +} + +func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) { + fg, err := p.ForegroundWithContext(ctx) + if err != nil { + return false, err + } + return !fg, err +} + // If interval is 0, return difference from last call(non-blocking). // If interval > 0, wait interval sec and return diffrence between start and end. func (p *Process) Percent(interval time.Duration) (float64, error) { diff --git a/process/process_darwin.go b/process/process_darwin.go index 509ab3b..b55c3d2 100644 --- a/process/process_darwin.go +++ b/process/process_darwin.go @@ -239,6 +239,25 @@ func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return r[0][0], err } + +func (p *Process) Foreground() (bool, error) { + return p.ForegroundWithContext(context.Background()) +} + +func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { + // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details + pid := p.Pid + ps, err := exec.LookPath("ps") + if err != nil { + return false, err + } + out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", string(pid)) + if err != nil { + return false, err + } + return strings.IndexByte(string(out), '+') != -1, nil +} + func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) } diff --git a/process/process_fallback.go b/process/process_fallback.go index ca8b72f..c49342e 100644 --- a/process/process_fallback.go +++ b/process/process_fallback.go @@ -114,6 +114,13 @@ func (p *Process) Status() (string, error) { func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } +func (p *Process) Foreground() (bool, error) { + return p.ForegroundWithContext(context.Background()) +} + +func (p *Process) ForegroundWithContext() (bool, error) { + return false, common.ErrNotImplementedError +} func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) } diff --git a/process/process_freebsd.go b/process/process_freebsd.go index af2b3b1..01f3659 100644 --- a/process/process_freebsd.go +++ b/process/process_freebsd.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "encoding/binary" + "os/exec" "strings" cpu "github.com/shirou/gopsutil/cpu" @@ -168,6 +169,25 @@ func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return s, nil } + +func (p *Process) Foreground() (bool, error) { + return p.ForegroundWithContext(context.Background()) +} + +func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { + // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details + pid := p.Pid + ps, err := exec.LookPath("ps") + if err != nil { + return false, err + } + out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", string(pid)) + if err != nil { + return false, err + } + return strings.IndexByte(string(out), '+') != -1, nil +} + func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) } diff --git a/process/process_linux.go b/process/process_linux.go index f844101..ecdd7b4 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -199,6 +199,28 @@ func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return p.status, nil } +// Foreground returns true if the process is in foreground, false otherwise. +func (p *Process) Foreground() (bool, error) { + return p.ForegroundWithContext(context.Background()) +} + +func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { + // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details + pid := p.Pid + statPath := common.HostProc(strconv.Itoa(int(pid)), "stat") + contents, err := ioutil.ReadFile(statPath) + if err != nil { + return false, err + } + fields := strings.Fields(string(contents)) + if len(fields) < 8 { + return false, fmt.Errorf("insufficient data in %s", statPath) + } + pgid := fields[4] + tpgid := fields[7] + return pgid == tpgid, nil +} + // Uids returns user ids of the process as a slice of the int func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) diff --git a/process/process_windows.go b/process/process_windows.go index 82aed37..3879eb4 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -250,6 +250,15 @@ func (p *Process) Status() (string, error) { func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + +func (p *Process) Foreground() (bool, error) { + return p.ForegroundWithContext(context.Background()) +} + +func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { + return false, common.ErrNotImplementedError +} + func (p *Process) Username() (string, error) { return p.UsernameWithContext(context.Background()) }