/ internal / tools / system_info_darwin.go
system_info_darwin.go
 1  package tools
 2  
 3  import (
 4  	"fmt"
 5  	"os/exec"
 6  	"strconv"
 7  	"strings"
 8  	"syscall"
 9  )
10  
11  func getMemoryInfo() string {
12  	// macOS: use sysctl for total memory
13  	out, err := exec.Command("sysctl", "-n", "hw.memsize").CombinedOutput()
14  	if err != nil {
15  		return ""
16  	}
17  	totalBytes, err := strconv.ParseUint(strings.TrimSpace(string(out)), 10, 64)
18  	if err != nil {
19  		return ""
20  	}
21  
22  	// Get page size and free pages from vm_stat
23  	pageSize := uint64(syscall.Getpagesize())
24  	vmOut, err := exec.Command("vm_stat").CombinedOutput()
25  	if err != nil {
26  		return fmt.Sprintf("Memory Total: %s\n", formatBytes(totalBytes))
27  	}
28  
29  	freePages := uint64(0)
30  	for _, line := range strings.Split(string(vmOut), "\n") {
31  		if strings.HasPrefix(line, "Pages free:") {
32  			val := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(line, "Pages free:"), "."))
33  			if n, err := strconv.ParseUint(val, 10, 64); err == nil {
34  				freePages = n
35  			}
36  		}
37  	}
38  	freeBytes := freePages * pageSize
39  
40  	return fmt.Sprintf("Memory Total: %s\nMemory Free: %s\n", formatBytes(totalBytes), formatBytes(freeBytes))
41  }
42  
43  func getDiskInfo() string {
44  	var stat syscall.Statfs_t
45  	if err := syscall.Statfs("/", &stat); err != nil {
46  		return ""
47  	}
48  	total := stat.Blocks * uint64(stat.Bsize)
49  	free := stat.Bavail * uint64(stat.Bsize)
50  	return fmt.Sprintf("Disk Total: %s\nDisk Free: %s\n", formatBytes(total), formatBytes(free))
51  }
52  
53  func formatBytes(b uint64) string {
54  	const (
55  		MB = 1024 * 1024
56  		GB = 1024 * MB
57  	)
58  	if b >= GB {
59  		return fmt.Sprintf("%.1f GB", float64(b)/float64(GB))
60  	}
61  	return fmt.Sprintf("%.1f MB", float64(b)/float64(MB))
62  }