1package sigar 2 3import ( 4 "bytes" 5 "fmt" 6 "os/exec" 7 "strconv" 8 "syscall" 9 "time" 10 "unsafe" 11 12 "github.com/cloudfoundry/gosigar/sys/windows" 13 "github.com/pkg/errors" 14) 15 16var ( 17 kernel32DLL = syscall.MustLoadDLL("kernel32") 18 19 procGetDiskFreeSpace = kernel32DLL.MustFindProc("GetDiskFreeSpaceW") 20 procGetSystemTimes = kernel32DLL.MustFindProc("GetSystemTimes") 21 procGetTickCount64 = kernel32DLL.MustFindProc("GetTickCount64") 22 procGlobalMemoryStatusEx = kernel32DLL.MustFindProc("GlobalMemoryStatusEx") 23 24 // processQueryLimitedInfoAccess is set to PROCESS_QUERY_INFORMATION for Windows 25 // 2003 and XP where PROCESS_QUERY_LIMITED_INFORMATION is unknown. For all newer 26 // OS versions it is set to PROCESS_QUERY_LIMITED_INFORMATION. 27 processQueryLimitedInfoAccess = windows.PROCESS_QUERY_LIMITED_INFORMATION 28) 29 30func (self *LoadAverage) Get() error { 31 return ErrNotImplemented 32} 33 34func (u *Uptime) Get() error { 35 r1, _, e1 := syscall.Syscall(procGetTickCount64.Addr(), 0, 0, 0, 0) 36 if e1 != 0 { 37 return error(e1) 38 } 39 u.Length = (time.Duration(r1) * time.Millisecond).Seconds() 40 return nil 41} 42 43type memorystatusex struct { 44 Length uint32 45 MemoryLoad uint32 46 TotalPhys uint64 47 AvailPhys uint64 48 TotalPageFile uint64 49 AvailPageFile uint64 50 TotalVirtual uint64 51 AvailVirtual uint64 52 AvailExtendedVirtual uint64 53} 54 55func (m *Mem) Get() error { 56 var x memorystatusex 57 x.Length = uint32(unsafe.Sizeof(x)) 58 r1, _, e1 := syscall.Syscall(procGlobalMemoryStatusEx.Addr(), 1, 59 uintptr(unsafe.Pointer(&x)), 60 0, 61 0, 62 ) 63 if err := checkErrno(r1, e1); err != nil { 64 return fmt.Errorf("GlobalMemoryStatusEx: %s", err) 65 } 66 m.Total = x.TotalPhys 67 m.Free = x.AvailPhys 68 m.ActualFree = m.Free 69 m.Used = m.Total - m.Free 70 m.ActualUsed = m.Used 71 return nil 72} 73 74func (s *Swap) Get() error { 75 const MB = 1024 * 1024 76 out, err := exec.Command("wmic", "pagefile", "list", "full").Output() 77 if err != nil { 78 return err 79 } 80 total, err := parseWmicOutput(out, []byte("AllocatedBaseSize")) 81 if err != nil { 82 return err 83 } 84 used, err := parseWmicOutput(out, []byte("CurrentUsage")) 85 if err != nil { 86 return err 87 } 88 s.Total = total * MB 89 s.Used = used * MB 90 s.Free = s.Total - s.Used 91 return nil 92} 93 94func parseWmicOutput(s, sep []byte) (uint64, error) { 95 bb := bytes.Split(s, []byte("\n")) 96 for i := 0; i < len(bb); i++ { 97 b := bytes.TrimSpace(bb[i]) 98 n := bytes.IndexByte(b, '=') 99 if n > 0 && bytes.Equal(sep, b[:n]) { 100 return strconv.ParseUint(string(b[n+1:]), 10, 64) 101 } 102 } 103 return 0, errors.New("parseWmicOutput: missing field: " + string(sep)) 104} 105 106func (c *Cpu) Get() error { 107 var ( 108 idleTime syscall.Filetime 109 kernelTime syscall.Filetime // Includes kernel and idle time. 110 userTime syscall.Filetime 111 ) 112 r1, _, e1 := syscall.Syscall(procGetSystemTimes.Addr(), 3, 113 uintptr(unsafe.Pointer(&idleTime)), 114 uintptr(unsafe.Pointer(&kernelTime)), 115 uintptr(unsafe.Pointer(&userTime)), 116 ) 117 if err := checkErrno(r1, e1); err != nil { 118 return fmt.Errorf("GetSystemTimes: %s", err) 119 } 120 121 c.Idle = uint64(idleTime.Nanoseconds()) 122 c.Sys = uint64(kernelTime.Nanoseconds()) - c.Idle 123 c.User = uint64(userTime.Nanoseconds()) 124 return nil 125} 126 127func (self *CpuList) Get() error { 128 return ErrNotImplemented 129} 130 131func (self *FileSystemList) Get() error { 132 return ErrNotImplemented 133} 134 135func (self *ProcList) Get() error { 136 return ErrNotImplemented 137} 138 139func (self *ProcState) Get(pid int) error { 140 return ErrNotImplemented 141} 142 143func (self *ProcMem) Get(pid int) error { 144 handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess|windows.PROCESS_VM_READ, false, uint32(pid)) 145 if err != nil { 146 return errors.Wrapf(err, "OpenProcess failed for pid=%v", pid) 147 } 148 defer syscall.CloseHandle(handle) 149 150 counters, err := windows.GetProcessMemoryInfo(handle) 151 if err != nil { 152 return errors.Wrapf(err, "GetProcessMemoryInfo failed for pid=%v", pid) 153 } 154 155 self.Resident = uint64(counters.WorkingSetSize) 156 self.Size = uint64(counters.PrivateUsage) 157 return nil 158} 159 160func (self *ProcTime) Get(pid int) error { 161 handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess, false, uint32(pid)) 162 if err != nil { 163 return errors.Wrapf(err, "OpenProcess failed for pid=%v", pid) 164 } 165 defer syscall.CloseHandle(handle) 166 167 var CPU syscall.Rusage 168 if err := syscall.GetProcessTimes(handle, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil { 169 return errors.Wrapf(err, "GetProcessTimes failed for pid=%v", pid) 170 } 171 172 // Windows epoch times are expressed as time elapsed since midnight on 173 // January 1, 1601 at Greenwich, England. This converts the Filetime to 174 // unix epoch in milliseconds. 175 self.StartTime = uint64(CPU.CreationTime.Nanoseconds() / 1e6) 176 177 // Convert to millis. 178 self.User = uint64(windows.FiletimeToDuration(&CPU.UserTime).Nanoseconds() / 1e6) 179 self.Sys = uint64(windows.FiletimeToDuration(&CPU.KernelTime).Nanoseconds() / 1e6) 180 self.Total = self.User + self.Sys 181 182 return nil 183} 184 185func (self *ProcArgs) Get(pid int) error { 186 return ErrNotImplemented 187} 188 189func (self *ProcExe) Get(pid int) error { 190 return ErrNotImplemented 191} 192 193func (fs *FileSystemUsage) Get(path string) error { 194 root, err := syscall.UTF16PtrFromString(path) 195 if err != nil { 196 return fmt.Errorf("FileSystemUsage (%s): %s", path, err) 197 } 198 199 var ( 200 SectorsPerCluster uint32 201 BytesPerSector uint32 202 203 // Free clusters available to the user 204 // associated with the calling thread. 205 NumberOfFreeClusters uint32 206 207 // Total clusters available to the user 208 // associated with the calling thread. 209 TotalNumberOfClusters uint32 210 ) 211 r1, _, e1 := syscall.Syscall6(procGetDiskFreeSpace.Addr(), 5, 212 uintptr(unsafe.Pointer(root)), 213 uintptr(unsafe.Pointer(&SectorsPerCluster)), 214 uintptr(unsafe.Pointer(&BytesPerSector)), 215 uintptr(unsafe.Pointer(&NumberOfFreeClusters)), 216 uintptr(unsafe.Pointer(&TotalNumberOfClusters)), 217 0, 218 ) 219 if err := checkErrno(r1, e1); err != nil { 220 return fmt.Errorf("FileSystemUsage (%s): %s", path, err) 221 } 222 223 m := uint64(SectorsPerCluster * BytesPerSector / 1024) 224 fs.Total = uint64(TotalNumberOfClusters) * m 225 fs.Free = uint64(NumberOfFreeClusters) * m 226 fs.Avail = fs.Free 227 fs.Used = fs.Total - fs.Free 228 229 return nil 230} 231 232func checkErrno(r1 uintptr, e1 error) error { 233 if r1 == 0 { 234 if e, ok := e1.(syscall.Errno); ok && e != 0 { 235 return e1 236 } 237 return syscall.EINVAL 238 } 239 return nil 240} 241