diff options
Diffstat (limited to 'vendor/github.com/keybase/go-ps/process_windows.go')
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_windows.go | 196 |
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 +} |