mirror of
https://github.com/oneclickvirt/basics.git
synced 2026-04-23 00:37:11 +08:00
fix: 适配MACOS多盘检测
This commit is contained in:
+126
-56
@@ -33,51 +33,59 @@ func getDiskInfo() ([]string, []string, []string, string, error) {
|
|||||||
var currentDiskInfo *DiskSingelInfo
|
var currentDiskInfo *DiskSingelInfo
|
||||||
// macOS 特殊适配
|
// macOS 特殊适配
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
// 获取所有APFS卷的挂载点
|
// 获取 APFS 容器信息
|
||||||
mountPoints := getMacOSMountPoints()
|
containers := getMacOSAPFSContainers()
|
||||||
for _, mountPoint := range mountPoints {
|
for _, container := range containers {
|
||||||
cmd := exec.Command("df", "-k", mountPoint)
|
if container.TotalBytes >= 200*1024*1024*1024 {
|
||||||
output, err := cmd.Output()
|
diskInfos = append(diskInfos, container)
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
lines := strings.Split(string(output), "\n")
|
// 检查是否包含根分区
|
||||||
if len(lines) >= 2 {
|
if container.BootPath != "" && (strings.Contains(container.BootPath, "disk3") || container.BootPath == "/" || currentDiskInfo == nil) {
|
||||||
fields := strings.Fields(lines[1])
|
bootPath = container.BootPath
|
||||||
if len(fields) >= 6 {
|
currentDiskInfo = &container
|
||||||
totalKB, err1 := strconv.ParseUint(fields[1], 10, 64)
|
}
|
||||||
usedKB, err2 := strconv.ParseUint(fields[2], 10, 64)
|
}
|
||||||
if err1 == nil && err2 == nil {
|
// 如果没有找到包含根分区的容器,使用 df 命令作为fallback
|
||||||
totalBytes := totalKB * 1024
|
if currentDiskInfo == nil {
|
||||||
usedBytes := usedKB * 1024
|
cmd := exec.Command("df", "-k", "/")
|
||||||
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
|
output, err := cmd.Output()
|
||||||
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
|
if err == nil {
|
||||||
var diskTotalStr, diskUsageStr string
|
lines := strings.Split(string(output), "\n")
|
||||||
if diskTotalGB < 1 {
|
if len(lines) >= 2 {
|
||||||
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
|
fields := strings.Fields(lines[1])
|
||||||
} else {
|
if len(fields) >= 6 {
|
||||||
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
|
totalKB, err1 := strconv.ParseUint(fields[1], 10, 64)
|
||||||
}
|
usedKB, err2 := strconv.ParseUint(fields[2], 10, 64)
|
||||||
if diskUsageGB < 1 {
|
if err1 == nil && err2 == nil {
|
||||||
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
|
totalBytes := totalKB * 1024
|
||||||
} else {
|
usedBytes := usedKB * 1024
|
||||||
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
|
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
|
||||||
}
|
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
|
||||||
percentage := float64(usedBytes) / float64(totalBytes) * 100
|
var diskTotalStr, diskUsageStr string
|
||||||
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%"
|
if diskTotalGB < 1 {
|
||||||
diskInfo := DiskSingelInfo{
|
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
|
||||||
TotalStr: diskTotalStr,
|
} else {
|
||||||
UsageStr: diskUsageStr,
|
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
|
||||||
PercentageStr: percentageStr,
|
}
|
||||||
BootPath: fields[0],
|
if diskUsageGB < 1 {
|
||||||
TotalBytes: totalBytes,
|
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
|
||||||
}
|
} else {
|
||||||
if mountPoint == "/" {
|
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
|
||||||
|
}
|
||||||
|
percentage := float64(usedBytes) / float64(totalBytes) * 100
|
||||||
|
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%"
|
||||||
|
diskInfo := DiskSingelInfo{
|
||||||
|
TotalStr: diskTotalStr,
|
||||||
|
UsageStr: diskUsageStr,
|
||||||
|
PercentageStr: percentageStr,
|
||||||
|
BootPath: fields[0],
|
||||||
|
TotalBytes: totalBytes,
|
||||||
|
}
|
||||||
bootPath = fields[0]
|
bootPath = fields[0]
|
||||||
currentDiskInfo = &diskInfo
|
currentDiskInfo = &diskInfo
|
||||||
}
|
if totalBytes >= 200*1024*1024*1024 {
|
||||||
if totalBytes >= 200*1024*1024*1024 {
|
diskInfos = append(diskInfos, diskInfo)
|
||||||
diskInfos = append(diskInfos, diskInfo)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,30 +296,92 @@ func getDiskInfo() ([]string, []string, []string, string, error) {
|
|||||||
return diskTotalStrs, diskUsageStrs, percentageStrs, bootPath, nil
|
return diskTotalStrs, diskUsageStrs, percentageStrs, bootPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMacOSMountPoints 获取macOS所有APFS卷的挂载点
|
// getMacOSAPFSContainers 获取macOS APFS容器信息
|
||||||
func getMacOSMountPoints() []string {
|
func getMacOSAPFSContainers() []DiskSingelInfo {
|
||||||
var mountPoints []string
|
var containers []DiskSingelInfo
|
||||||
mountPoints = append(mountPoints, "/")
|
cmd := exec.Command("diskutil", "apfs", "list")
|
||||||
cmd := exec.Command("diskutil", "list")
|
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mountPoints
|
return containers
|
||||||
}
|
}
|
||||||
lines := strings.Split(string(output), "\n")
|
lines := strings.Split(string(output), "\n")
|
||||||
|
var currentContainer *DiskSingelInfo
|
||||||
|
var totalBytes, usedBytes uint64
|
||||||
|
var containerDisk string
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if strings.Contains(line, "APFS Volume") && !strings.Contains(line, "Preboot") && !strings.Contains(line, "Recovery") && !strings.Contains(line, "VM") {
|
line = strings.TrimSpace(line)
|
||||||
|
if strings.Contains(line, "Container disk") {
|
||||||
|
if currentContainer != nil {
|
||||||
|
containers = append(containers, *currentContainer)
|
||||||
|
}
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) >= 4 {
|
if len(fields) >= 2 {
|
||||||
volumeName := fields[3]
|
containerDisk = fields[1]
|
||||||
if volumeName == "Macintosh" || volumeName == "Data" {
|
currentContainer = &DiskSingelInfo{
|
||||||
continue
|
BootPath: containerDisk,
|
||||||
}
|
}
|
||||||
mountPoint := "/Volumes/" + volumeName
|
}
|
||||||
mountPoints = append(mountPoints, mountPoint)
|
} else if currentContainer != nil {
|
||||||
|
if strings.Contains(line, "Size (Capacity Ceiling):") {
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
sizeStr := strings.TrimSpace(parts[1])
|
||||||
|
if strings.Contains(sizeStr, " B ") {
|
||||||
|
sizeFields := strings.Fields(sizeStr)
|
||||||
|
if len(sizeFields) >= 1 {
|
||||||
|
if size, err := strconv.ParseUint(sizeFields[0], 10, 64); err == nil {
|
||||||
|
totalBytes = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "Capacity In Use By Volumes:") {
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
usedStr := strings.TrimSpace(parts[1])
|
||||||
|
if strings.Contains(usedStr, " B ") {
|
||||||
|
usedFields := strings.Fields(usedStr)
|
||||||
|
if len(usedFields) >= 1 {
|
||||||
|
if used, err := strconv.ParseUint(usedFields[0], 10, 64); err == nil {
|
||||||
|
usedBytes = used
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "Snapshot Mount Point:") && strings.Contains(line, "/") {
|
||||||
|
currentContainer.BootPath = containerDisk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if currentContainer != nil && totalBytes > 0 && usedBytes > 0 {
|
||||||
|
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
|
||||||
|
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
|
||||||
|
var diskTotalStr, diskUsageStr string
|
||||||
|
if diskTotalGB < 1 {
|
||||||
|
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
|
||||||
|
} else {
|
||||||
|
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
|
||||||
|
}
|
||||||
|
if diskUsageGB < 1 {
|
||||||
|
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
|
||||||
|
} else {
|
||||||
|
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
|
||||||
|
}
|
||||||
|
percentage := float64(usedBytes) / float64(totalBytes) * 100
|
||||||
|
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%"
|
||||||
|
currentContainer.TotalStr = diskTotalStr
|
||||||
|
currentContainer.UsageStr = diskUsageStr
|
||||||
|
currentContainer.PercentageStr = percentageStr
|
||||||
|
currentContainer.TotalBytes = totalBytes
|
||||||
|
totalBytes = 0
|
||||||
|
usedBytes = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mountPoints
|
if currentContainer != nil {
|
||||||
|
containers = append(containers, *currentContainer)
|
||||||
|
}
|
||||||
|
return containers
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSize 解析尺寸字符串为字节数
|
// parseSize 解析尺寸字符串为字节数
|
||||||
|
|||||||
@@ -15,13 +15,11 @@ func GetGPUModel() ([]string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, card := range gi.GraphicsCards {
|
for _, card := range gi.GraphicsCards {
|
||||||
if card.DeviceInfo == nil {
|
if card.DeviceInfo == nil {
|
||||||
return nil, errors.New("Cannot find device info")
|
return nil, errors.New("Cannot find device info")
|
||||||
}
|
}
|
||||||
gpuModel = append(gpuModel, card.DeviceInfo.Product.Name)
|
gpuModel = append(gpuModel, card.DeviceInfo.Product.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gpuModel, nil
|
return gpuModel, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ func extractGPUInfo(cmd *exec.Cmd) ([]string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile(`"model"\s*=\s*["<]?"([^">]+)"[">]?`)
|
re := regexp.MustCompile(`"model"\s*=\s*["<]?"([^">]+)"[">]?`)
|
||||||
matches := re.FindAllSubmatch(gi, -1)
|
matches := re.FindAllSubmatch(gi, -1)
|
||||||
var modelNames []string
|
var modelNames []string
|
||||||
@@ -29,7 +28,6 @@ func GetGPUModel() ([]string, error) {
|
|||||||
vendorNames := []string{
|
vendorNames := []string{
|
||||||
"AMD", "Intel", "Nvidia", "Apple",
|
"AMD", "Intel", "Nvidia", "Apple",
|
||||||
}
|
}
|
||||||
|
|
||||||
ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator")
|
ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator")
|
||||||
gi, err := extractGPUInfo(ioreg)
|
gi, err := extractGPUInfo(ioreg)
|
||||||
if err != nil || len(gi) == 0 {
|
if err != nil || len(gi) == 0 {
|
||||||
@@ -39,7 +37,6 @@ func GetGPUModel() ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gpuModel []string
|
var gpuModel []string
|
||||||
for _, model := range gi {
|
for _, model := range gi {
|
||||||
for _, vendor := range vendorNames {
|
for _, vendor := range vendorNames {
|
||||||
|
|||||||
@@ -43,15 +43,12 @@ func GetGPUModel() ([]string, error) {
|
|||||||
vendorNames := []string{
|
vendorNames := []string{
|
||||||
"AMD", "Intel", "Nvidia", "Apple",
|
"AMD", "Intel", "Nvidia", "Apple",
|
||||||
}
|
}
|
||||||
|
|
||||||
key := C.CString("model")
|
key := C.CString("model")
|
||||||
defer C.free(unsafe.Pointer(key))
|
defer C.free(unsafe.Pointer(key))
|
||||||
|
|
||||||
gi, err := extractGPUInfo(key)
|
gi, err := extractGPUInfo(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var gpuModel []string
|
var gpuModel []string
|
||||||
for _, model := range gi {
|
for _, model := range gi {
|
||||||
for _, vendor := range vendorNames {
|
for _, vendor := range vendorNames {
|
||||||
|
|||||||
Reference in New Issue
Block a user