//go:build linux package system import ( "bufio" "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 } 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 } }