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 "" }