summaryrefslogtreecommitdiff
path: root/vendor/github.com/keybase/go-ps/process_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/keybase/go-ps/process_windows.go')
-rw-r--r--vendor/github.com/keybase/go-ps/process_windows.go196
1 files changed, 196 insertions, 0 deletions
diff --git a/vendor/github.com/keybase/go-ps/process_windows.go b/vendor/github.com/keybase/go-ps/process_windows.go
new file mode 100644
index 0000000..e4d89e3
--- /dev/null
+++ b/vendor/github.com/keybase/go-ps/process_windows.go
@@ -0,0 +1,196 @@
+// +build windows
+
+package ps
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// Windows API functions
+var (
+ modKernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procCloseHandle = modKernel32.NewProc("CloseHandle")
+ procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot")
+ procProcess32First = modKernel32.NewProc("Process32FirstW")
+ procProcess32Next = modKernel32.NewProc("Process32NextW")
+ procModule32First = modKernel32.NewProc("Module32FirstW")
+ procModule32Next = modKernel32.NewProc("Module32NextW")
+)
+
+// Some constants from the Windows API
+const (
+ ERROR_NO_MORE_FILES = 0x12
+ MAX_PATH = 260
+ MAX_MODULE_NAME32 = 255
+)
+
+type PROCESSENTRY32 struct {
+ Size uint32
+ CntUsage uint32
+ ProcessID uint32
+ DefaultHeapID uintptr
+ ModuleID uint32
+ CntThreads uint32
+ ParentProcessID uint32
+ PriorityClassBase int32
+ Flags uint32
+ ExeFile [MAX_PATH]uint16
+}
+
+// WindowsProcess is an implementation of Process for Windows.
+type WindowsProcess struct {
+ pid int
+ ppid int
+ exe string
+}
+
+// Pid returns process id
+func (p *WindowsProcess) Pid() int {
+ return p.pid
+}
+
+// PPid returns parent process id
+func (p *WindowsProcess) PPid() int {
+ return p.ppid
+}
+
+// Executable returns process executable name
+func (p *WindowsProcess) Executable() string {
+ return p.exe
+}
+
+// Path returns path to process executable
+func (p *WindowsProcess) Path() (string, error) {
+ processModules, err := modules(p.pid)
+ if err != nil {
+ return "", err
+ }
+ if len(processModules) == 0 {
+ return "", fmt.Errorf("No modules found for process")
+ }
+ return processModules[0].path, nil
+}
+
+func ptrToString(c []uint16) string {
+ i := 0
+ for {
+ if c[i] == 0 {
+ return syscall.UTF16ToString(c[:i])
+ }
+ i++
+ }
+}
+
+func newWindowsProcess(e *PROCESSENTRY32) *WindowsProcess {
+ return &WindowsProcess{
+ pid: int(e.ProcessID),
+ ppid: int(e.ParentProcessID),
+ exe: ptrToString(e.ExeFile[:]),
+ }
+}
+
+func findProcess(pid int) (Process, error) {
+ return findProcessWithFn(processes, pid)
+}
+
+func findProcessWithFn(processesFn processesFn, pid int) (Process, error) {
+ ps, err := processesFn()
+ if err != nil {
+ return nil, fmt.Errorf("Error listing processes: %s", err)
+ }
+
+ for _, p := range ps {
+ if p.Pid() == pid {
+ return p, nil
+ }
+ }
+
+ return nil, nil
+}
+
+func processes() ([]Process, error) {
+ handle, _, _ := procCreateToolhelp32Snapshot.Call(
+ 0x00000002,
+ 0)
+ if handle < 0 {
+ return nil, syscall.GetLastError()
+ }
+ defer procCloseHandle.Call(handle)
+
+ var entry PROCESSENTRY32
+ entry.Size = uint32(unsafe.Sizeof(entry))
+ ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry)))
+ if ret == 0 {
+ return nil, fmt.Errorf("Error retrieving process info.")
+ }
+
+ results := make([]Process, 0, 50)
+ for {
+ results = append(results, newWindowsProcess(&entry))
+
+ ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry)))
+ if ret == 0 {
+ break
+ }
+ }
+
+ return results, nil
+}
+
+// MODULEENTRY32 is the Windows API structure that contains a modules's
+// information.
+type MODULEENTRY32 struct {
+ Size uint32
+ ModuleID uint32
+ ProcessID uint32
+ GlblcntUsage uint32
+ ProccntUsage uint32
+ ModBaseAddr *uint8
+ ModBaseSize uint32
+ HModule uintptr
+ SzModule [MAX_MODULE_NAME32 + 1]uint16
+ SzExePath [MAX_PATH]uint16
+}
+
+type windowsModule struct {
+ name string
+ path string
+}
+
+func newWindowsModule(e *MODULEENTRY32) windowsModule {
+ return windowsModule{
+ name: ptrToString(e.SzModule[:]),
+ path: ptrToString(e.SzExePath[:]),
+ }
+}
+
+func modules(pid int) ([]windowsModule, error) {
+ handle, _, _ := procCreateToolhelp32Snapshot.Call(
+ 0x00000008, // TH32CS_SNAPMODULE
+ uintptr(uint32(pid)))
+ if handle < 0 {
+ return nil, syscall.GetLastError()
+ }
+ defer procCloseHandle.Call(handle)
+
+ var entry MODULEENTRY32
+ entry.Size = uint32(unsafe.Sizeof(entry))
+ ret, _, _ := procModule32First.Call(handle, uintptr(unsafe.Pointer(&entry)))
+ if ret == 0 {
+ return nil, fmt.Errorf("Error retrieving module info")
+ }
+
+ results := make([]windowsModule, 0, 50)
+ for {
+ results = append(results, newWindowsModule(&entry))
+
+ ret, _, _ := procModule32Next.Call(handle, uintptr(unsafe.Pointer(&entry)))
+ if ret == 0 {
+ break
+ }
+ }
+
+ return results, nil
+}