diff --git a/README.rst b/README.rst index 75364ff..6b2fb11 100644 --- a/README.rst +++ b/README.rst @@ -73,30 +73,30 @@ Current Status - pid_exists (linux, freebsd) - Process class - - pid (linux, freebsd, windows) - - ppid (linux) - - name (linux) - - cmdline (linux) - - create_time (linux) - - status (linux) - - cwd (linux) - - exe (linux, freebsd) - - uids (linux) - - gids (linux) - - terminal (linux) - - nice (linux) - - num_fds (linux) - - num_threads (linux) - - cpu_times (linux) - - memory_info (linux) - - memory_info_ex (linux) - - Memory_maps() (linux) <- this is a function - - open_files (linux) - - send_signal (linux, freebsd) - - suspend (linux, freebsd) - - resume (linux, freebsd) - - terminate (linux, freebsd) - - kill (linux, freebsd) + - Pid (linux, freebsd, windows) + - Ppid (linux) + - Name (linux) + - Cmdline (linux) + - Create_time (linux) + - Status (linux) + - Cwd (linux) + - Exe (linux, freebsd) + - Uids (linux) + - Gids (linux) + - Terminal (linux) + - Nice (linux) + - Num_fds (linux) + - Num_threads (linux) + - Cpu_times (linux) + - Memory_info (linux) + - Memory_info_ex (linux) + - Memory_maps() (linux) + - Open_files (linux) + - Send_signal (linux, freebsd) + - Suspend (linux, freebsd) + - Resume (linux, freebsd) + - Terminate (linux, freebsd) + - Kill (linux, freebsd) - not yet diff --git a/common.go b/common.go index cfb977f..1ff89c8 100644 --- a/common.go +++ b/common.go @@ -9,6 +9,7 @@ package gopsutil import ( "bufio" "os" + "strconv" "strings" ) @@ -55,3 +56,15 @@ func byteToString(orig []byte) string { return string(orig[l:n]) } } + +// Parse to int32 without error +func parseInt32(val string) int32 { + vv, _ := strconv.ParseInt(val, 10, 32) + return int32(vv) +} + +// Parse to uint64 without error +func parseUint64(val string) uint64 { + vv, _ := strconv.ParseInt(val, 10, 64) + return uint64(vv) +} diff --git a/common_windows.go b/common_windows.go index 2f981d1..04fea1d 100644 --- a/common_windows.go +++ b/common_windows.go @@ -7,7 +7,11 @@ import ( ) var ( - modKernel32 = syscall.NewLazyDLL("kernel32.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + modNt = syscall.NewLazyDLL("ntdll.dll") + + procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") + procNtQuerySystemInformation = modNt.NewProc("NtQuerySystemInformation") ) type FILETIME struct { diff --git a/cpu_windows.go b/cpu_windows.go index 0859d40..ba88542 100644 --- a/cpu_windows.go +++ b/cpu_windows.go @@ -7,11 +7,6 @@ import ( "unsafe" ) -var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") -) - func Cpu_times() ([]CPU_TimesStat, error) { ret := make([]CPU_TimesStat, 0) diff --git a/disk_windows.go b/disk_windows.go index e7e4f31..133eb39 100644 --- a/disk_windows.go +++ b/disk_windows.go @@ -12,7 +12,7 @@ var ( procGetDiskFreeSpaceExW = modkernel32.NewProc("GetDiskFreeSpaceExW") procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") procGetDriveType = modkernel32.NewProc("GetDriveTypeW") - provGetVolumeInformation = modKernel32.NewProc("GetVolumeInformationW") + provGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW") ) var ( diff --git a/host_windows.go b/host_windows.go index 92b2abb..f03ba30 100644 --- a/host_windows.go +++ b/host_windows.go @@ -10,8 +10,8 @@ import ( ) var ( - procGetSystemTimeAsFileTime = modKernel32.NewProc("GetSystemTimeAsFileTime") - procGetTickCount = modKernel32.NewProc("GetTickCount") + procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime") + procGetTickCount = modkernel32.NewProc("GetTickCount") ) func HostInfo() (HostInfoStat, error) { diff --git a/mem_windows.go b/mem_windows.go index 6052136..3c30c79 100644 --- a/mem_windows.go +++ b/mem_windows.go @@ -8,7 +8,7 @@ import ( ) var ( - procGlobalMemoryStatusEx = modKernel32.NewProc("GlobalMemoryStatusEx") + procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") ) type MEMORYSTATUSEX struct { diff --git a/process.go b/process.go index 534fc39..a053a6b 100644 --- a/process.go +++ b/process.go @@ -2,38 +2,6 @@ package gopsutil type Process struct { Pid int32 `json:"pid"` - Ppid int32 `json:"ppid"` - Name string `json:"name"` - Exe string `json:"exe"` - Cmdline string `json:"cmdline"` - Create_time int64 `json:"create_time"` - // Parent Process // FIXME: recursive - Status string `json:"status"` - Cwd string `json:"cwd"` - Username string `json:"username"` - Uids []int32 `json:"uids"` - Gids []int32 `json:"gids"` - Terminal string `json:"terminal"` - Nice int32 `json:"nice"` - Ionice int32 `json:"ionice"` - Rlimit []RlimitStat `json:"rlimit"` - Io_counters Io_countersStat `json:"io_counter"` - Num_ctx_switches int32 `json:"num_ctx_switches"` - Num_fds int32 `json:"num_fds"` - Num_handles int32 `json:"num_handles"` - Num_Threads int32 `json:"nunm_threads"` - // Threads map[string]string `json:"threads"` - Cpu_times CPU_TimesStat `json:"cpu_times"` - // Cpu_percent `json:"cpu_percent"` - Cpu_affinity []int32 `json:"cpu_affinity"` - Memory_info Memory_infoStat `json:"memory_info"` - Memory_info_ex Memory_info_exStat `json:"memori_info_ex"` - Memory_percent float32 `json:"memory_percent"` - Memory_maps []Memory_mapsStat `json:"memory_maps"` - // Children []Process // FIXME: recursive `json:"children"` - Open_files []Open_filesStat `json:"open_files"` - Connections []Net_connectionStat `json:"connections"` - Is_running bool `json:"is_running"` } type Open_filesStat struct { diff --git a/process_linux.go b/process_linux.go index 6f9a661..1a4158a 100644 --- a/process_linux.go +++ b/process_linux.go @@ -8,7 +8,6 @@ import ( "path/filepath" "strconv" "strings" - "sync" "syscall" ) @@ -41,32 +40,153 @@ type Memory_mapsStat struct { Swap uint64 `json:"swap"` } -type fillFunc func(pid int32, p *Process) error - +// Create new Process instance +// This only stores Pid func NewProcess(pid int32) (*Process, error) { p := &Process{ Pid: int32(pid), } + return p, nil +} - // Fill Process information from fillFuncs - var wg sync.WaitGroup - funcs := []fillFunc{fillFromStat, fillFromStatus, fillFromfd, - fillFromCmdline, fillFromStatm, fillFromCwd, fillFromExe} - - wg.Add(len(funcs)) - for _, f := range funcs { - go func(f fillFunc) { - wg.Done() - f(pid, p) - }(f) +func (p *Process) Ppid() (int32, error) { + _, ppid, _, _, _, err := p.fillFromStat() + if err != nil{ + return -1, err + } + return ppid, nil +} +func (p *Process) Name() (string, error) { + name, _, _, _, _, err := p.fillFromStatus() + if err != nil { + return "", err + } + return name, nil +} +func (p *Process) Exe() (string, error) { + return p.fillFromExe() +} +func (p *Process) Cmdline() (string, error) { + return p.fillFromCmdline() +} +func (p *Process) Cwd() (string, error) { + return p.fillFromCwd() +} +func (p *Process) Parent() (*Process, error) { + return nil, nil +} +func (p *Process) Status() (string, error) { + _, status, _, _, _, err := p.fillFromStatus() + if err != nil { + return "", err + } + return status, nil +} +func (p *Process) Username() (string, error) { + return "", nil +} +func (p *Process) Uids() ([]int32, error) { + _, _, uids, _, _, err := p.fillFromStatus() + if err != nil { + return nil, err + } + return uids, nil +} +func (p *Process) Gids() ([]int32, error) { + _, _, _, gids, _, err := p.fillFromStatus() + if err != nil { + return nil, err + } + return gids, nil +} +func (p *Process) Terminal() (string, error) { + terminal, _, _, _, _, err := p.fillFromStat() + if err != nil{ + return "", err } - wg.Wait() + return terminal, nil +} +func (p *Process) Nice() (int32, error) { + _, _, _, _, nice, err := p.fillFromStat() + if err != nil{ + return 0, err + } + return nice, nil +} +func (p *Process) Ionice() (int32, error) { + return 0, nil +} +func (p *Process) Rlimit() ([]RlimitStat, error) { + return nil, nil +} +func (p *Process) Io_counters() (*Io_countersStat, error) { + return nil, nil +} +func (p *Process) Num_ctx_switches() (int32, error) { + return 0, nil +} +func (p *Process) Num_fds() (int32, error) { + return 0, nil +} +func (p *Process) Num_Threads() (int32, error) { + _, _, _, _, num_threads, err := p.fillFromStatus() + if err != nil { + return 0, err + } + return num_threads, nil +} +func (p *Process) Threads() (map[string]string, error) { + ret := make(map[string]string, 0) + return ret, nil +} +func (p *Process) Cpu_times() (*CPU_TimesStat, error) { + _, _, cpu_times, _, _, err := p.fillFromStat() + if err != nil{ + return nil, err + } + return cpu_times, nil +} +func (p *Process) Cpu_percent() (int32, error) { + return 0, nil +} +func (p *Process) Cpu_affinity() ([]int32, error) { + return nil, nil +} +func (p *Process) Memory_info() (*Memory_infoStat, error) { + mem_info, _, err := p.fillFromStatm() + if err != nil { + return nil, err + } + return mem_info, nil +} +func (p *Process) Memory_info_ex() (*Memory_info_exStat, error) { + _, mem_info_ex, err := p.fillFromStatm() + if err != nil { + return nil, err + } + return mem_info_ex, nil +} +func (p *Process) Memory_percent() (float32, error) { + return 0, nil +} - return p, nil +func (p *Process) Children() ([]*Process, error) { + return nil, nil +} + +func (p *Process) Open_files() ([]Open_filesStat, error) { + return nil, nil +} + +func (p *Process) Connections() ([]Net_connectionStat, error) { + return nil, nil +} + +func (p *Process) Is_running() (bool, error) { + return true, nil } // Get memory maps from /proc/(pid)/smaps -// This is a function. Because Memory map information is very big. func (p *Process) Memory_Maps() (*[]Memory_mapsStat, error) { pid := p.Pid ret := make([]Memory_mapsStat, 0) @@ -132,107 +252,97 @@ func (p *Process) Memory_Maps() (*[]Memory_mapsStat, error) { return &ret, nil } -// Parse to int32 without error -func parseInt32(val string) int32 { - vv, _ := strconv.ParseInt(val, 10, 32) - return int32(vv) -} - -// Parse to uint64 without error -func parseUint64(val string) uint64 { - vv, _ := strconv.ParseInt(val, 10, 64) - return uint64(vv) -} +/** +** Internal functions +**/ // Get num_fds from /proc/(pid)/fd -func fillFromfd(pid int32, p *Process) error { +func (p *Process) fillFromfd() (int32, []*Open_filesStat, error) { + pid := p.Pid statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "fd") d, err := os.Open(statPath) if err != nil { - return err + return 0, nil, err } defer d.Close() fnames, err := d.Readdirnames(-1) - num_fds := len(fnames) - p.Num_fds = int32(num_fds) + num_fds := int32(len(fnames)) - openfiles := make([]Open_filesStat, num_fds) - for _, fd := range fnames{ + openfiles := make([]*Open_filesStat, num_fds) + for _, fd := range fnames { fpath := filepath.Join(statPath, fd) filepath, err := os.Readlink(fpath) if err != nil { continue } - o := Open_filesStat{ + o := &Open_filesStat{ Path: filepath, - Fd: parseUint64(fd), + Fd: parseUint64(fd), } openfiles = append(openfiles, o) } - p.Open_files = openfiles - - return nil + return num_fds, openfiles, nil } // Get cwd from /proc/(pid)/cwd -func fillFromCwd(pid int32, p *Process) error { +func (p *Process) fillFromCwd() (string, error) { + pid := p.Pid cwdPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "cwd") cwd, err := os.Readlink(cwdPath) if err != nil { - return err + return "", err } - p.Cwd = string(cwd) - - return nil + return string(cwd), nil } // Get exe from /proc/(pid)/exe -func fillFromExe(pid int32, p *Process) error { +func (p *Process) fillFromExe() (string, error) { + pid := p.Pid exePath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "exe") exe, err := os.Readlink(exePath) if err != nil { - return err + return "", err } - p.Exe = string(exe) - - return nil + return string(exe), nil } // Get cmdline from /proc/(pid)/cmdline -func fillFromCmdline(pid int32, p *Process) error { +func (p *Process) fillFromCmdline() (string, error) { + pid := p.Pid cmdPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { - return err + return "", err } // remove \u0000 - p.Cmdline = strings.TrimFunc(string(cmdline), func(r rune) bool { + ret := strings.TrimFunc(string(cmdline), func(r rune) bool { if r == '\u0000' { return true } return false }) - return nil + return ret, nil } // Get memory info from /proc/(pid)/statm -func fillFromStatm(pid int32, p *Process) error { +func (p *Process) fillFromStatm() (*Memory_infoStat, *Memory_info_exStat, error) { + pid := p.Pid memPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "statm") contents, err := ioutil.ReadFile(memPath) if err != nil { - return err + return nil, nil, err } fields := strings.Split(string(contents), " ") rss := parseUint64(fields[0]) * PAGESIZE vms := parseUint64(fields[1]) * PAGESIZE - p.Memory_info = Memory_infoStat{ + mem_info := &Memory_infoStat{ RSS: rss, VMS: vms, } - p.Memory_info_ex = Memory_info_exStat{ + mem_info_ex := &Memory_info_exStat{ RSS: rss, VMS: vms, Shared: parseUint64(fields[2]) * PAGESIZE, @@ -241,18 +351,24 @@ func fillFromStatm(pid int32, p *Process) error { Dirty: parseUint64(fields[5]) * PAGESIZE, } - return nil + return mem_info, mem_info_ex, nil } // Get various status from /proc/(pid)/status -func fillFromStatus(pid int32, p *Process) error { +func (p *Process) fillFromStatus() (string, string, []int32, []int32, int32, error) { + pid := p.Pid statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) if err != nil { - return err + return "", "", nil, nil, 0, err } lines := strings.Split(string(contents), "\n") + name := "" + status := "" + var num_threads int32 + uids := make([]int32, 0) + gids := make([]int32, 0) for _, line := range lines { field := strings.Split(line, ":") if len(field) < 2 { @@ -261,47 +377,49 @@ func fillFromStatus(pid int32, p *Process) error { // fmt.Printf("%s ->__%s__\n", field[0], strings.Trim(field[1], " \t")) switch field[0] { case "Name": - p.Name = strings.Trim(field[1], " \t") + name = strings.Trim(field[1], " \t") case "State": // get between "(" and ")" s := strings.Index(field[1], "(") + 1 e := strings.Index(field[1], "(") + 1 - p.Status = field[1][s:e] + status = field[1][s:e] // case "PPid": // filled by fillFromStat case "Uid": for _, i := range strings.Split(field[1], "\t") { - p.Uids = append(p.Uids, parseInt32(i)) + uids = append(uids, parseInt32(i)) } case "Gid": for _, i := range strings.Split(field[1], "\t") { - p.Gids = append(p.Uids, parseInt32(i)) + gids = append(gids, parseInt32(i)) } case "Threads": - p.Num_Threads = parseInt32(field[1]) + num_threads = parseInt32(field[1]) } } - return nil + return name, status, uids, gids, num_threads, nil } -func fillFromStat(pid int32, p *Process) error { +func (p *Process) fillFromStat() (string, int32, *CPU_TimesStat, int64, int32, error) { + pid := p.Pid statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "stat") contents, err := ioutil.ReadFile(statPath) if err != nil { - return err + return "", 0, nil, 0, 0, err } fields := strings.Fields(string(contents)) termmap, err := getTerminalMap() + terminal := "" if err == nil { - p.Terminal = termmap[parseUint64(fields[6])] + terminal = termmap[parseUint64(fields[6])] } - p.Ppid = parseInt32(fields[3]) + ppid := parseInt32(fields[3]) utime, _ := strconv.ParseFloat(fields[13], 64) stime, _ := strconv.ParseFloat(fields[14], 64) - p.Cpu_times = CPU_TimesStat{ + cpu_times := &CPU_TimesStat{ Cpu: "cpu", User: float32(utime * (1000 / CLOCK_TICKS)), System: float32(stime * (1000 / CLOCK_TICKS)), @@ -309,33 +427,14 @@ func fillFromStat(pid int32, p *Process) error { boot_time, _ := Boot_time() ctime := ((parseUint64(fields[21]) / uint64(CLOCK_TICKS)) + uint64(boot_time)) * 1000 - p.Create_time = int64(ctime) + create_time := int64(ctime) // p.Nice = parseInt32(fields[18]) // use syscall instead of parse Stat file - nice, _ := syscall.Getpriority(PRIO_PROCESS, int(pid)) - p.Nice = int32(nice) // FIXME: is this true? - - return nil -} - -func processes() ([]*Process, error) { - ret := make([]*Process, 0) - - pids, err := Pids() - if err != nil { - return ret, err - } + snice, _ := syscall.Getpriority(PRIO_PROCESS, int(pid)) + nice := int32(snice) // FIXME: is this true? - for _, pid := range pids { - p, err := NewProcess(pid) - if err != nil { - continue // FIXME: should return error? - } - ret = append(ret, p) - } - - return ret, nil + return terminal, ppid, cpu_times, create_time, nice, nil } func Pids() ([]int32, error) { diff --git a/process_test.go b/process_test.go index 6be9165..779b60f 100644 --- a/process_test.go +++ b/process_test.go @@ -6,7 +6,6 @@ import ( "os" "runtime" "testing" - "syscall" ) func Test_Pids(t *testing.T) { @@ -68,12 +67,19 @@ func Test_Process_memory_maps(t *testing.T) { } -func Test_SendSignal(t *testing.T){ +func Test_Process_Ppid(t *testing.T) { check_pid := os.Getpid() + if runtime.GOOS == "windows" { + check_pid = 0 + } + ret, err := NewProcess(int32(check_pid)) - p, _ := NewProcess(int32(check_pid)) - err := p.Send_signal(syscall.SIGCONT) - if err != nil{ - t.Errorf("send signal %v", err) + v, err := ret.Ppid() + if err != nil { + t.Errorf("memory map get error %v", err) } + if v == 0 { + t.Errorf("memory map get error %v", v) + } + } diff --git a/process_test_posix.go b/process_test_posix.go new file mode 100644 index 0000000..75e9223 --- /dev/null +++ b/process_test_posix.go @@ -0,0 +1,19 @@ +// +build linux freebsd + +package gopsutil + +import ( + "os" + "syscall" + "testing" +) + +func Test_SendSignal(t *testing.T) { + check_pid := os.Getpid() + + p, _ := NewProcess(int32(check_pid)) + err := p.Send_signal(syscall.SIGCONT) + if err != nil { + t.Errorf("send signal %v", err) + } +} diff --git a/process_windows.go b/process_windows.go index 901ca8c..52b1428 100644 --- a/process_windows.go +++ b/process_windows.go @@ -3,16 +3,12 @@ package gopsutil import ( + "errors" "fmt" "syscall" "unsafe" -) -var ( - procCloseHandle = modKernel32.NewProc("CloseHandle") - procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot") - procProcess32First = modKernel32.NewProc("Process32FirstW") - procProcess32Next = modKernel32.NewProc("Process32NextW") + "github.com/shirou/w32" ) const ( @@ -33,22 +29,20 @@ type PROCESSENTRY32 struct { SzExeFile [MAX_PATH]uint16 } -/* type SYSTEM_PROCESS_INFORMATION struct { - ULONG NextEntryOffset; - ULONG NumberOfThreads; - BYTE Reserved1[48]; - PVOID Reserved2[3]; - HANDLE UniqueProcessId; - PVOID Reserved3; - ULONG HandleCount; - BYTE Reserved4[4]; - PVOID Reserved5[11]; - SIZE_T PeakPagefileUsage; - SIZE_T PrivatePageCount; - LARGE_INTEGER Reserved6[6]; -} -*/ + NextEntryOffset uint64 + NumberOfThreads uint64 + Reserved1 [48]byte + Reserved2 [3]byte + UniqueProcessId uintptr + Reserved3 uintptr + HandleCount uint64 + Reserved4 [4]byte + Reserved5 [11]byte + PeakPagefileUsage uint64 + PrivatePageCount uint64 + Reserved6 [6]uint64 +} // Memory_info_ex is different between OSes type Memory_info_exStat struct { @@ -58,6 +52,7 @@ type Memory_mapsStat struct { } func Pids() ([]int32, error) { + ret := make([]int32, 0) procs, err := processes() @@ -71,59 +66,202 @@ func Pids() ([]int32, error) { return ret, nil } +func (p *Process) Ppid() (int32, error) { + return 0, nil +} +func (p *Process) Name() (string, error) { + name := "" + return name, nil +} +func (p *Process) Exe() (string, error) { + return "", nil +} +func (p *Process) Cmdline() (string, error) { + return "", nil +} +func (p *Process) Cwd() (string, error) { + return "", nil +} +func (p *Process) Parent() (*Process, error) { + return p, nil +} +func (p *Process) Status() (string, error) { + return "", nil +} +func (p *Process) Username() (string, error) { + return "", nil +} +func (p *Process) Uids() ([]int32, error) { + uids := make([]int32, 0) + return uids, nil +} +func (p *Process) Gids() ([]int32, error) { + gids := make([]int32, 0) + return gids, nil +} +func (p *Process) Terminal() (string, error) { + return "", nil +} +func (p *Process) Nice() (int32, error) { + return 0, nil +} +func (p *Process) Ionice() (int32, error) { + return 0, nil +} +func (p *Process) Rlimit() ([]RlimitStat, error) { + rlimit := make([]RlimitStat, 0) + return rlimit, nil +} +func (p *Process) Io_counters() (*Io_countersStat, error) { + return nil, nil +} +func (p *Process) Num_ctx_switches() (int32, error) { + return 0, nil +} +func (p *Process) Num_fds() (int32, error) { + return 0, nil +} +func (p *Process) Num_Threads() (int32, error) { + return 0, nil +} +func (p *Process) Threads() (map[string]string, error) { + ret := make(map[string]string, 0) + return ret, nil +} +func (p *Process) Cpu_times() (*CPU_TimesStat, error) { + return nil, nil +} +func (p *Process) Cpu_percent() (int32, error) { + return 0, nil +} +func (p *Process) Cpu_affinity() ([]int32, error) { + return nil, nil +} +func (p *Process) Memory_info() (*Memory_infoStat, error) { + return nil, nil +} +func (p *Process) Memory_info_ex() (*Memory_info_exStat, error) { + return nil, nil +} +func (p *Process) Memory_percent() (float32, error) { + return 0, nil +} + +func (p *Process) Children() ([]*Process, error) { + return nil, nil +} + +func (p *Process) Open_files() ([]Open_filesStat, error) { + return nil, nil +} + +func (p *Process) Connections() ([]Net_connectionStat, error) { + return nil, nil +} + +func (p *Process) Is_running() (bool, error) { + return true, nil +} + func (p *Process) Memory_Maps() (*[]Memory_mapsStat, error) { - ret := make([]Memory_mapsStat, 0) - return &ret, nil + return nil, nil } func NewProcess(pid int32) (*Process, error) { p := &Process{Pid: pid} - if (pid == 0) || (pid == 4) { - p.Cmdline = "" - } return p, nil } +func (p *Process) Send_signal(sig syscall.Signal) error { + return nil +} + +func (p *Process) Suspend() error { + return nil +} +func (p *Process) Resume() error { + return nil +} +func (p *Process) Terminate() error { + return nil +} +func (p *Process) Kill() error { + return nil +} func copy_params(pe32 *PROCESSENTRY32, p *Process) error { - p.Ppid = int32(pe32.Th32ParentProcessID) + // p.Ppid = int32(pe32.Th32ParentProcessID) + + return nil +} + +func printModuleInfo(me32 *w32.MODULEENTRY32) { + fmt.Printf("Exe: %s\n", syscall.UTF16ToString(me32.SzExePath[:])) +} + +func printProcessInfo(pid uint32) error { + snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPMODULE, pid) + if snap == 0 { + return errors.New("snapshot could not be created") + } + defer w32.CloseHandle(snap) + + var me32 w32.MODULEENTRY32 + me32.Size = uint32(unsafe.Sizeof(me32)) + if !w32.Module32First(snap, &me32) { + return errors.New("module information retrieval failed") + } + + fmt.Printf("pid:%d\n", pid) + printModuleInfo(&me32) + for w32.Module32Next(snap, &me32) { + printModuleInfo(&me32) + } return nil } // Get processes -// This is borrowed from go-ps func processes() ([]*Process, error) { - handle, _, _ := procCreateToolhelp32Snapshot.Call( - 0x00000002, - 0) - if handle < 0 { + ps := make([]uint32, 255) + var read uint32 = 0 + if w32.EnumProcesses(ps, uint32(len(ps)), &read) == false { + println("could not read processes") return nil, syscall.GetLastError() } - defer procCloseHandle.Call(handle) - - var entry PROCESSENTRY32 - entry.DwSize = 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) - for { - pid := int32(entry.Th32ProcessID) - p, err := NewProcess(pid) + for _, pid := range ps[:read/4] { + if pid == 0 { + continue + } + + p, err := NewProcess(int32(pid)) if err != nil { break } - copy_params(&entry, p) results = append(results, p) - ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry))) - if ret == 0 { - break - } + // printProcessInfo(pid) } return results, nil } + +func get_proc_info(pid int32) (*SYSTEM_PROCESS_INFORMATION, error) { + initialBufferSize := uint64(0x4000) + bufferSize := initialBufferSize + buffer := make([]byte, bufferSize) + + var sys_proc_info SYSTEM_PROCESS_INFORMATION + ret, _, _ := procNtQuerySystemInformation.Call( + uintptr(unsafe.Pointer(&sys_proc_info)), + uintptr(unsafe.Pointer(&buffer[0])), + uintptr(unsafe.Pointer(&bufferSize)), + uintptr(unsafe.Pointer(&bufferSize))) + if ret != 0 { + return nil, syscall.GetLastError() + } + + return &sys_proc_info, nil +} diff --git a/windows_memo.rst b/windows_memo.rst new file mode 100644 index 0000000..38abed8 --- /dev/null +++ b/windows_memo.rst @@ -0,0 +1,36 @@ +Windows memo +===================== + +Size +---------- + +DWORD + 32-bit unsigned integer +DWORDLONG + 64-bit unsigned integer +DWORD_PTR + unsigned long type for pointer precision +DWORD32 + 32-bit unsigned integer +DWORD64 + 64-bit unsigned integer +HALF_PTR + _WIN64 = int, else short +INT + 32-bit signed integer +INT_PTR + _WIN64 = __int64 else int +LONG + 32-bit signed integer +LONGLONG + 64-bit signed integer +LONG_PTR + _WIN64 = __int64 else long +SHORT + 16-bit integer +SIZE_T + maximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T; +SSIZE_T + signed version of SIZE_T. typedef LONG_PTR SSIZE_T; +WORD + 16-bit unsigned integer \ No newline at end of file