github.com/PandaGoAdmin/utils@v0.0.0-20211208134815-d5461603a00f/os_linux.go (about) 1 // +build linux 2 3 package kgo 4 5 import ( 6 "bufio" 7 "fmt" 8 "golang.org/x/sys/unix" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "regexp" 13 "runtime" 14 "strconv" 15 "strings" 16 "syscall" 17 ) 18 19 // getPidByInode 根据套接字的inode获取PID.须root权限. 20 func getPidByInode(inode string, procDirs []string) (pid int) { 21 if len(procDirs) == 0 { 22 procDirs, _ = filepath.Glob("/proc/[0-9]*/fd/[0-9]*") 23 } 24 25 re := regexp.MustCompile(inode) 26 for _, item := range procDirs { 27 path, _ := os.Readlink(item) 28 out := re.FindString(path) 29 if len(out) != 0 { 30 pid, _ = strconv.Atoi(strings.Split(item, "/")[2]) 31 break 32 } 33 } 34 35 return pid 36 } 37 38 // getProcessPathByPid 根据PID获取进程的执行路径. 39 func getProcessPathByPid(pid int) (res string) { 40 exe := fmt.Sprintf("/proc/%d/exe", pid) 41 res, _ = os.Readlink(exe) 42 43 return 44 } 45 46 // MemoryUsage 获取内存使用率,单位字节. 47 // 参数 virtual(仅支持linux),是否取虚拟内存. 48 // used为已用, 49 // free为空闲, 50 // total为总数. 51 func (ko *LkkOS) MemoryUsage(virtual bool) (used, free, total uint64) { 52 if virtual { 53 // 虚拟机的内存 54 contents, err := ioutil.ReadFile("/proc/meminfo") 55 if err == nil { 56 lines := strings.Split(string(contents), "\n") 57 for _, line := range lines { 58 fields := strings.Fields(line) 59 if len(fields) == 3 { 60 val, _ := strconv.ParseUint(fields[1], 10, 64) // kB 61 62 if strings.HasPrefix(fields[0], "MemTotal") { 63 total = val * 1024 64 } else if strings.HasPrefix(fields[0], "MemFree") { 65 free = val * 1024 66 } 67 } 68 } 69 70 //计算已用内存 71 used = total - free 72 } 73 } else { 74 // 真实物理机内存 75 sysi := &syscall.Sysinfo_t{} 76 err := syscall.Sysinfo(sysi) 77 if err == nil { 78 total = sysi.Totalram * uint64(sysi.Unit) 79 free = sysi.Freeram * uint64(sysi.Unit) 80 used = total - free 81 } 82 } 83 84 return 85 } 86 87 // CpuUsage 获取CPU使用率(darwin系统必须使用cgo),单位jiffies(节拍数). 88 // user为用户态(用户进程)的运行时间, 89 // idle为空闲时间, 90 // total为累计时间. 91 func (ko *LkkOS) CpuUsage() (user, idle, total uint64) { 92 contents, _ := ioutil.ReadFile("/proc/stat") 93 if len(contents) > 0 { 94 lines := strings.Split(string(contents), "\n") 95 for _, line := range lines { 96 fields := strings.Fields(line) 97 if fields[0] == "cpu" { 98 //CPU指标:user,nice, system, idle, iowait, irq, softirq 99 // cpu 130216 19944 162525 1491240 3784 24749 17773 0 0 0 100 101 numFields := len(fields) 102 for i := 1; i < numFields; i++ { 103 val, _ := strconv.ParseUint(fields[i], 10, 64) 104 total += val // tally up all the numbers to get total ticks 105 if i == 1 { 106 user = val 107 } else if i == 4 { // idle is the 5th field in the cpu line 108 idle = val 109 } 110 } 111 break 112 } 113 } 114 } 115 116 return 117 } 118 119 // DiskUsage 获取磁盘(目录)使用情况,单位字节.参数path为路径. 120 // used为已用, 121 // free为空闲, 122 // total为总数. 123 func (ko *LkkOS) DiskUsage(path string) (used, free, total uint64) { 124 fs := &syscall.Statfs_t{} 125 err := syscall.Statfs(path, fs) 126 if err == nil { 127 total = fs.Blocks * uint64(fs.Bsize) 128 free = fs.Bfree * uint64(fs.Bsize) 129 used = total - free 130 } 131 132 return 133 } 134 135 // Uptime 获取系统运行时间,秒. 136 func (ko *LkkOS) Uptime() (uint64, error) { 137 sysinfo := &unix.Sysinfo_t{} 138 if err := unix.Sysinfo(sysinfo); err != nil { 139 return 0, err 140 } 141 return uint64(sysinfo.Uptime), nil 142 } 143 144 // GetBiosInfo 获取BIOS信息. 145 // 注意:Mac机器没有BIOS信息,它使用EFI. 146 func (ko *LkkOS) GetBiosInfo() *BiosInfo { 147 return &BiosInfo{ 148 Vendor: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/bios_vendor"))), 149 Version: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/bios_version"))), 150 Date: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/bios_date"))), 151 } 152 } 153 154 // GetBoardInfo 获取Board信息. 155 func (ko *LkkOS) GetBoardInfo() *BoardInfo { 156 return &BoardInfo{ 157 Name: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/board_name"))), 158 Vendor: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/board_vendor"))), 159 Version: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/board_version"))), 160 Serial: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/board_serial"))), 161 AssetTag: strings.TrimSpace(string(KFile.ReadFirstLine("/sys/class/dmi/id/board_asset_tag"))), 162 } 163 } 164 165 // GetCpuInfo 获取CPU信息. 166 func (ko *LkkOS) GetCpuInfo() *CpuInfo { 167 var res = &CpuInfo{ 168 Vendor: "", 169 Model: "", 170 Speed: "", 171 Cache: 0, 172 Cpus: 0, 173 Cores: 0, 174 Threads: 0, 175 } 176 177 res.Threads = uint(runtime.NumCPU()) 178 f, err := os.Open("/proc/cpuinfo") 179 if err == nil { 180 cpu := make(map[string]bool) 181 core := make(map[string]bool) 182 var cpuID string 183 184 s := bufio.NewScanner(f) 185 for s.Scan() { 186 if sl := cpuRegTwoColumns.Split(s.Text(), 2); sl != nil { 187 switch sl[0] { 188 case "physical id": 189 cpuID = sl[1] 190 cpu[cpuID] = true 191 case "core id": 192 coreID := fmt.Sprintf("%s/%s", cpuID, sl[1]) 193 core[coreID] = true 194 case "vendor_id": 195 if res.Vendor == "" { 196 res.Vendor = sl[1] 197 } 198 case "model name": 199 if res.Model == "" { 200 // CPU model, as reported by /proc/cpuinfo, can be a bit ugly. Clean up... 201 model := cpuRegExtraSpace.ReplaceAllLiteralString(sl[1], " ") 202 res.Model = strings.Replace(model, "- ", "-", 1) 203 } 204 case "cpu MHz": 205 if res.Speed == "" { 206 res.Speed = sl[1] 207 } 208 case "cache size": 209 if res.Cache == 0 { 210 if m := cpuRegCacheSize.FindStringSubmatch(sl[1]); m != nil { 211 if cache, err := strconv.ParseUint(m[1], 10, 64); err == nil { 212 res.Cache = uint(cache) 213 } 214 } 215 } 216 } 217 } 218 } 219 220 res.Cpus = uint(len(cpu)) 221 res.Cores = uint(len(core)) 222 } 223 defer func() { 224 _ = f.Close() 225 }() 226 227 return res 228 } 229 230 // GetPidByPort 根据端口号获取监听的进程PID. 231 // linux可能要求root权限; 232 // darwin依赖lsof; 233 // windows依赖netstat. 234 func (ko *LkkOS) GetPidByPort(port int) (pid int) { 235 files := []string{ 236 "/proc/net/tcp", 237 "/proc/net/udp", 238 "/proc/net/tcp6", 239 "/proc/net/udp6", 240 } 241 242 procDirs, _ := filepath.Glob("/proc/[0-9]*/fd/[0-9]*") 243 for _, fpath := range files { 244 lines, _ := KFile.ReadInArray(fpath) 245 for _, line := range lines[1:] { 246 fields := strings.Fields(line) 247 if len(fields) < 10 { 248 continue 249 } 250 251 //非 LISTEN 监听状态 252 if fields[3] != "0A" { 253 continue 254 } 255 256 //本地ip和端口 257 ipport := strings.Split(fields[1], ":") 258 locPort, _ := KConv.Hex2Dec(ipport[1]) 259 260 // 非该端口 261 if int(locPort) != port { 262 continue 263 } 264 265 pid = getPidByInode(fields[9], procDirs) 266 if pid > 0 { 267 return 268 } 269 } 270 } 271 272 return 273 }