Files
basics/system/disk.go
2025-06-28 13:39:57 +00:00

220 lines
6.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package system
import (
"os/exec"
"runtime"
"strconv"
"strings"
"github.com/shirou/gopsutil/v4/disk"
)
// getDiskInfo 获取硬盘信息
func getDiskInfo() (string, string, string, string, error) {
var diskTotalStr, diskUsageStr, percentageStr, bootPath string
// macOS 特殊适配
if runtime.GOOS == "darwin" {
cmd := exec.Command("df", "-h", "/")
output, err := cmd.Output()
if err == nil {
lines := strings.Split(string(output), "\n")
if len(lines) >= 2 {
fields := strings.Fields(lines[1])
if len(fields) >= 5 {
bootPath = fields[0]
diskTotalStr = fields[1]
diskUsageStr = fields[2]
percentageStr = fields[4]
if strings.Contains(percentageStr, "%") {
percentageStr = strings.ReplaceAll(percentageStr, "%", "%%")
}
return diskTotalStr, diskUsageStr, percentageStr, bootPath, nil
}
}
}
}
// BSD系统特殊处理
if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd" {
cmd := exec.Command("df", "-h", "/")
output, err := cmd.Output()
if err == nil {
lines := strings.Split(string(output), "\n")
if len(lines) >= 2 {
fields := strings.Fields(lines[1])
if len(fields) >= 5 {
bootPath = fields[0]
diskTotalStr = fields[1]
diskUsageStr = fields[2]
percentageStr = fields[4]
if percentageStr != "" && strings.Contains(percentageStr, "%") {
percentageStr = strings.ReplaceAll(percentageStr, "%", "%%")
}
return diskTotalStr, diskUsageStr, percentageStr, bootPath, nil
}
}
}
}
tempDiskTotal, tempDiskUsage := getDiskTotalAndUsed()
diskTotalGB := float64(tempDiskTotal) / (1024 * 1024 * 1024)
diskUsageGB := float64(tempDiskUsage) / (1024 * 1024 * 1024)
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"
}
if runtime.GOOS == "windows" {
parts, err := disk.Partitions(true)
if err != nil {
bootPath = ""
} else {
for _, part := range parts {
if part.Fstype == "tmpfs" {
continue
}
usageStat, err := disk.Usage(part.Mountpoint)
if err != nil {
continue
}
if usageStat.Total > 0 {
bootPath = part.Mountpoint
break
}
}
}
} else {
// 特殊处理 docker、lxc 等虚拟化使用 overlay 挂载的情况
cmd := exec.Command("df", "-x", "tmpfs", "/")
output, err := cmd.Output()
if err == nil {
lines := strings.Split(string(output), "\n")
if len(lines) >= 2 {
fields := strings.Split(strings.TrimSpace(lines[1]), " ")
var nonEmptyFields []string
for _, field := range fields {
if field != "" {
nonEmptyFields = append(nonEmptyFields, field)
}
}
if len(nonEmptyFields) > 0 && nonEmptyFields[0] != "" {
bootPath = nonEmptyFields[0]
if strings.Contains(bootPath, "overlay") && len(nonEmptyFields) >= 5 {
tpDiskTotal, err1 := strconv.Atoi(nonEmptyFields[1])
tpDiskUsage, err2 := strconv.Atoi(nonEmptyFields[2])
if err1 == nil && err2 == nil {
diskTotalGB = float64(tpDiskTotal) / (1024 * 1024)
diskUsageGB = float64(tpDiskUsage) / (1024 * 1024)
if diskTotalGB < 1 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
percentageStr = nonEmptyFields[4]
} else {
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
percentageStr = nonEmptyFields[4]
}
if diskUsageGB < 1 {
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
} else {
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
}
}
}
}
}
}
}
if percentageStr != "" && strings.Contains(percentageStr, "%") {
percentageStr = strings.ReplaceAll(percentageStr, "%", "%%")
}
return diskTotalStr, diskUsageStr, percentageStr, bootPath, nil
}
func getDiskTotalAndUsed() (total uint64, used uint64) {
// MacOS特殊处理直接用 df -k /
if runtime.GOOS == "darwin" {
cmd := exec.Command("df", "-k", "/")
out, err := cmd.CombinedOutput()
if err == nil {
lines := strings.Split(string(out), "\n")
if len(lines) >= 2 {
fields := strings.Fields(lines[1])
if len(fields) >= 6 {
totalKB, err1 := strconv.ParseUint(fields[1], 10, 64)
usedKB, err2 := strconv.ParseUint(fields[2], 10, 64)
if err1 == nil && err2 == nil {
total = totalKB * 1024
used = usedKB * 1024
return
}
}
}
}
}
devices := make(map[string]string)
// 使用默认过滤规则
diskList, _ := disk.Partitions(false)
for _, d := range diskList {
fsType := strings.ToLower(d.Fstype)
// 不统计 K8s 的虚拟挂载点https://github.com/shirou/gopsutil/issues/1007
if devices[d.Device] == "" && isListContainsStr(expectDiskFsTypes, fsType) && !strings.Contains(d.Mountpoint, "/var/lib/kubelet") {
devices[d.Device] = d.Mountpoint
}
}
for _, mountPath := range devices {
diskUsageOf, err := disk.Usage(mountPath)
if err == nil {
total += diskUsageOf.Total
used += diskUsageOf.Used
}
}
// 回退到根路径的获取方法
if total == 0 && used == 0 {
var cmd *exec.Cmd
// BSD系统使用特定参数
if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd" {
cmd = exec.Command("df", "-k", "/")
} else {
cmd = exec.Command("df")
}
out, err := cmd.CombinedOutput()
if err == nil {
s := strings.Split(string(out), "\n")
for _, c := range s {
info := strings.Fields(c)
if len(info) == 6 {
if info[5] == "/" {
total, _ = strconv.ParseUint(info[1], 0, 64)
used, _ = strconv.ParseUint(info[2], 0, 64)
// 默认获取的是1K块为单位的.
total = total * 1024
used = used * 1024
break
}
} else if len(info) == 5 && (runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd") {
// BSD系统df输出格式可能只有5列
if info[4] == "/" {
total, _ = strconv.ParseUint(info[1], 0, 64)
used, _ = strconv.ParseUint(info[2], 0, 64)
total = total * 1024
used = used * 1024
break
}
}
}
}
}
return
}
func isListContainsStr(list []string, str string) bool {
for i := 0; i < len(list); i++ {
if strings.Contains(str, list[i]) {
return true
}
}
return false
}