127 lines
2.7 KiB
Go
127 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"go.wit.com/log"
|
|
)
|
|
|
|
type DevInfo struct {
|
|
Name string
|
|
IsRaw bool
|
|
Type string
|
|
Parent string // raw device if this entry is a partition
|
|
}
|
|
|
|
func doDrives2() {
|
|
parts, err := parseProcPartitions()
|
|
if err != nil {
|
|
log.Printf("Error reading /proc/partitions: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Determine raw devices and type
|
|
devs := make(map[string]*DevInfo)
|
|
for _, p := range parts {
|
|
devs[p.Name] = &DevInfo{Name: p.Name}
|
|
}
|
|
|
|
for _, info := range devs {
|
|
sysPath := filepath.Join("/sys/block", info.Name)
|
|
if exists(sysPath) {
|
|
info.IsRaw = true
|
|
typ := detectType(sysPath)
|
|
info.Type = typ
|
|
} else {
|
|
info.IsRaw = false
|
|
info.Parent = findParent(info.Name, devs)
|
|
}
|
|
}
|
|
|
|
for _, info := range devs {
|
|
devPath := "/dev/" + info.Name
|
|
if info.IsRaw {
|
|
addDrive(devPath, log.Sprintf("-> %-8s (raw)", info.Type))
|
|
} else {
|
|
if info.Parent != "" {
|
|
log.Printf("%-12s -> partition of /dev/%s\n", devPath, info.Parent)
|
|
} else {
|
|
log.Printf("%-12s -> unknown (no parent found)\n", devPath)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
// parseProcPartitions parses /proc/partitions entries
|
|
func parseProcPartitions() ([]struct {
|
|
Name string
|
|
}, error) {
|
|
f, err := os.Open("/proc/partitions")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
var parts []struct{ Name string }
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" || strings.HasPrefix(line, "major") {
|
|
continue
|
|
}
|
|
fields := strings.Fields(line)
|
|
if len(fields) < 4 {
|
|
continue
|
|
}
|
|
parts = append(parts, struct{ Name string }{Name: fields[3]})
|
|
}
|
|
return parts, scanner.Err()
|
|
}
|
|
*/
|
|
|
|
// exists checks if the given path exists
|
|
func exists(path string) bool {
|
|
_, err := os.Lstat(path)
|
|
return err == nil
|
|
}
|
|
|
|
// detectType determines device type by resolving sysPath and inspecting parent directories
|
|
func detectType(sysPath string) string {
|
|
resolved, err := filepath.EvalSymlinks(sysPath)
|
|
if err != nil {
|
|
return "unknown"
|
|
}
|
|
resolved = filepath.ToSlash(resolved)
|
|
|
|
switch {
|
|
case strings.Contains(resolved, "/nvme"):
|
|
return "NVMe"
|
|
case strings.Contains(resolved, "/mmc_host") || strings.Contains(resolved, "/mmc"):
|
|
return "MMC/SD"
|
|
case strings.Contains(resolved, "/usb"):
|
|
return "USB"
|
|
case strings.Contains(resolved, "/loop"):
|
|
return "Loop"
|
|
case strings.Contains(resolved, "/ram"):
|
|
return "RAM disk"
|
|
default:
|
|
return "SCSI/SATA"
|
|
}
|
|
}
|
|
|
|
// findParent identifies the raw device for a partition, based on name heuristics
|
|
func findParent(name string, devs map[string]*DevInfo) string {
|
|
for candidate := range devs {
|
|
if candidate == name {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(name, candidate) {
|
|
return candidate
|
|
}
|
|
}
|
|
return ""
|
|
}
|