From b8c40ac83c71bb08c277d6cb58ab9b234df33019 Mon Sep 17 00:00:00 2001 From: Chris Gilling Date: Sat, 27 Feb 2016 17:52:24 -0800 Subject: [PATCH] process: add CmdlineSlice function for linux + freebsd This allows for getting more exact information about each argument especially if there are arguments that have spaces in them. This was not implemented for darwin or for windows because they both currently have not way of properly parsing the cmdline string. Darwin parses the output of 'ps' which is already whitespace segmented, and windows just has the cmdline string. --- process/process_darwin.go | 3 +++ process/process_freebsd.go | 19 +++++++++++++++++++ process/process_linux.go | 30 ++++++++++++++++++++++++++++++ process/process_test.go | 13 +++++++++++++ process/process_windows.go | 4 +++- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/process/process_darwin.go b/process/process_darwin.go index 414ea98..f2bd0a8 100644 --- a/process/process_darwin.go +++ b/process/process_darwin.go @@ -88,6 +88,9 @@ func (p *Process) Cmdline() (string, error) { } return strings.Join(r[0], " "), err } +func (p *Process) CmdlineSlice() ([]string, error) { + return nil, common.NotImplementedError +} func (p *Process) CreateTime() (int64, error) { return 0, common.NotImplementedError } diff --git a/process/process_freebsd.go b/process/process_freebsd.go index 9835bc9..4989867 100644 --- a/process/process_freebsd.go +++ b/process/process_freebsd.go @@ -54,6 +54,7 @@ func (p *Process) Name() (string, error) { func (p *Process) Exe() (string, error) { return "", common.NotImplementedError } + func (p *Process) Cmdline() (string, error) { mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid} buf, _, err := common.CallSyscall(mib) @@ -69,6 +70,24 @@ func (p *Process) Cmdline() (string, error) { return strings.Join(ret, " "), nil } + +func (p *Process) CmdlineSlice() ([]string, error) { + mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid} + buf, _, err := common.CallSyscall(mib) + if err != nil { + return nil, err + } + if buf[len(buf)-1] == 0 { + buf = buf[:len(buf)-1] + } + parts := bytes.Split(buf, []byte{0}) + var strParts []string + for _, p := range parts { + strParts = append(strParts, string(p)) + } + + return strParts, nil +} func (p *Process) CreateTime() (int64, error) { return 0, common.NotImplementedError } diff --git a/process/process_linux.go b/process/process_linux.go index 1783d2f..7c6bb29 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -3,6 +3,7 @@ package process import ( + "bytes" "encoding/json" "errors" "fmt" @@ -84,9 +85,19 @@ func (p *Process) Name() (string, error) { func (p *Process) Exe() (string, error) { return p.fillFromExe() } + +// Cmdline returns the command line arguments of the process as a string with +// each argument separated by 0x20 ascii character. func (p *Process) Cmdline() (string, error) { return p.fillFromCmdline() } + +// CmdlineSlice returns the command line arguments of the process as a slice with each +// element being an argument. +func (p *Process) CmdlineSlice() ([]string, error) { + return p.fillSliceFromCmdline() +} + func (p *Process) CreateTime() (int64, error) { _, _, _, createTime, _, err := p.fillFromStat() if err != nil { @@ -403,6 +414,25 @@ func (p *Process) fillFromCmdline() (string, error) { return strings.Join(ret, " "), nil } +func (p *Process) fillSliceFromCmdline() ([]string, error) { + pid := p.Pid + cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") + cmdline, err := ioutil.ReadFile(cmdPath) + if err != nil { + return nil, err + } + if cmdline[len(cmdline)-1] == 0 { + cmdline = cmdline[:len(cmdline)-1] + } + parts := bytes.Split(cmdline, []byte{0}) + var strParts []string + for _, p := range parts { + strParts = append(strParts, string(p)) + } + + return strParts, nil +} + // Get IO status from /proc/(pid)/io func (p *Process) fillFromIO() (*IOCountersStat, error) { pid := p.Pid diff --git a/process/process_test.go b/process/process_test.go index 129204f..c5aac11 100644 --- a/process/process_test.go +++ b/process/process_test.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/user" + "reflect" "runtime" "strings" "sync" @@ -120,6 +121,18 @@ func Test_Process_CmdLine(t *testing.T) { } } +func Test_Process_CmdLineSlice(t *testing.T) { + p := testGetProcess() + + v, err := p.CmdlineSlice() + if err != nil { + t.Fatalf("geting cmdline slice error %v", err) + } + if !reflect.DeepEqual(v, os.Args) { + t.Errorf("returned cmdline slice not as expected:\nexp: %v\ngot: %v", os.Args, v) + } +} + func Test_Process_Ppid(t *testing.T) { p := testGetProcess() diff --git a/process/process_windows.go b/process/process_windows.go index 51a0ee1..6fd972e 100644 --- a/process/process_windows.go +++ b/process/process_windows.go @@ -144,7 +144,9 @@ func (p *Process) Cmdline() (string, error) { } return *dst[0].CommandLine, nil } - +func (p *Process) CmdlineSlice() ([]string, error) { + return nil, common.NotImplementedError +} func (p *Process) CreateTime() (int64, error) { dst, err := GetWin32Proc(p.Pid) if err != nil { -- GitLab