112 lines
2.6 KiB
Go
112 lines
2.6 KiB
Go
//go:build linux
|
|
|
|
package system
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
// GetInfo reads system memory and disk usage.
|
|
// hddPath is the mount path for external HDD; if empty, HDD info is skipped.
|
|
func GetInfo(hddPath string) SystemInfo {
|
|
info := SystemInfo{}
|
|
|
|
// --- Memory from /proc/meminfo ---
|
|
readMemInfo(&info)
|
|
|
|
// --- Root filesystem disk usage ---
|
|
readDiskUsage("/", &info.DiskTotalGB, &info.DiskUsedGB, &info.DiskAvailGB, &info.DiskPercent)
|
|
|
|
// --- HDD disk usage (if configured) ---
|
|
if hddPath != "" {
|
|
info.HDDConfigured = true
|
|
readDiskUsage(hddPath, &info.HDDTotalGB, &info.HDDUsedGB, &info.HDDAvailGB, &info.HDDPercent)
|
|
}
|
|
|
|
return info
|
|
}
|
|
|
|
// GetTotalMemoryMB reads total system memory from /proc/meminfo.
|
|
func GetTotalMemoryMB() (int, error) {
|
|
info := SystemInfo{}
|
|
readMemInfo(&info)
|
|
if info.TotalMemMB == 0 {
|
|
return 0, fmt.Errorf("could not read MemTotal from /proc/meminfo")
|
|
}
|
|
return int(info.TotalMemMB), nil
|
|
}
|
|
|
|
func readMemInfo(info *SystemInfo) {
|
|
f, err := os.Open("/proc/meminfo")
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer f.Close()
|
|
|
|
var totalKB, availKB uint64
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
switch {
|
|
case strings.HasPrefix(line, "MemTotal:"):
|
|
totalKB = parseMemLine(line)
|
|
case strings.HasPrefix(line, "MemAvailable:"):
|
|
availKB = parseMemLine(line)
|
|
}
|
|
if totalKB > 0 && availKB > 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
if totalKB > 0 {
|
|
info.TotalMemMB = totalKB / 1024
|
|
info.AvailMemMB = availKB / 1024
|
|
info.UsedMemMB = info.TotalMemMB - info.AvailMemMB
|
|
info.MemPercent = float64(info.UsedMemMB) / float64(info.TotalMemMB) * 100
|
|
}
|
|
}
|
|
|
|
// parseMemLine extracts the kB value from a /proc/meminfo line like "MemTotal: 16384000 kB"
|
|
func parseMemLine(line string) uint64 {
|
|
// Remove label prefix up to ':'
|
|
parts := strings.SplitN(line, ":", 2)
|
|
if len(parts) < 2 {
|
|
return 0
|
|
}
|
|
valStr := strings.TrimSpace(parts[1])
|
|
valStr = strings.TrimSuffix(valStr, " kB")
|
|
valStr = strings.TrimSpace(valStr)
|
|
|
|
var val uint64
|
|
for _, c := range valStr {
|
|
if c >= '0' && c <= '9' {
|
|
val = val*10 + uint64(c-'0')
|
|
}
|
|
}
|
|
return val
|
|
}
|
|
|
|
func readDiskUsage(path string, totalGB, usedGB, availGB *float64, percent *float64) {
|
|
var stat syscall.Statfs_t
|
|
if err := syscall.Statfs(path, &stat); err != nil {
|
|
return
|
|
}
|
|
|
|
bsize := uint64(stat.Bsize)
|
|
total := stat.Blocks * bsize
|
|
avail := stat.Bavail * bsize
|
|
used := total - (stat.Bfree * bsize) // Bfree includes reserved blocks
|
|
|
|
const gb = 1024 * 1024 * 1024
|
|
*totalGB = float64(total) / gb
|
|
*usedGB = float64(used) / gb
|
|
*availGB = float64(avail) / gb
|
|
if total > 0 {
|
|
*percent = float64(used) / float64(total) * 100
|
|
}
|
|
}
|