package main import ( "bufio" "io/fs" "os" "path/filepath" "strings" "go.wit.com/log" ) func doDrives() { parts, err := parseProcPartitions() if err != nil { panic(err) } for _, p := range parts { log.Printf("RAW Device: /dev/%s\tSize: %d KiB\n", p.Name, p.Blocks) devname := "/dev/" + p.Name if blkpb := me.pb.FindByName(devname); blkpb != nil { blkpb.SizeBytes = uint64(p.Blocks) * 1024 } } blockDir := "/sys/block" mounts := getMountedDevices() log.Info("doDrives()", mounts) err = filepath.WalkDir(blockDir, func(path string, d fs.DirEntry, err error) error { if path == blockDir { return nil // skip root } if d.IsDir() && filepath.Dir(path) == blockDir { dev := d.Name() devPath := "/dev/" + dev log.Printf("Drive: %s\n", devPath) // Look for partitions partitions, err := filepath.Glob(filepath.Join(blockDir, dev, dev+"*")) if err != nil { return err } hasPartition := false used := false for _, part := range partitions { partName := filepath.Base(part) partDev := "/dev/" + partName if partName == dev { log.Printf(" SKIP MAIN Partition: %s\n", partDev) continue // skip the main device } hasPartition = true isMounted := mounts[partDev] log.Printf(" Partition: %s [%v]\n", partDev, isMounted) if isMounted { used = true } } if !hasPartition { log.Println(" No partitions found.") } if !used { log.Println(" * Drive appears to be unused.") } } return nil }) if err != nil { panic(err) } } // getMountedDevices reads /proc/self/mountinfo and returns a map of mounted device paths func getMountedDevices() map[string]bool { f, err := os.Open("/proc/self/mountinfo") if err != nil { panic(err) } defer f.Close() mounted := make(map[string]bool) scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() fields := strings.Fields(line) if len(fields) < 10 { continue } // Device path is after the last '-' token for i, field := range fields { if field == "-" && i+2 < len(fields) { dev := fields[i+2] if strings.HasPrefix(dev, "/dev/") { mounted[dev] = true } break } } } return mounted } type Partition struct { Major int Minor int Blocks int64 Name string } func parseProcPartitions() ([]Partition, error) { f, err := os.Open("/proc/partitions") if err != nil { return nil, err } defer f.Close() var partitions []Partition scanner := bufio.NewScanner(f) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if strings.HasPrefix(line, "major") || line == "" { continue // Skip header and empty lines } var p Partition _, err := log.Sscanf(line, "%d %d %d %s", &p.Major, &p.Minor, &p.Blocks, &p.Name) if err != nil { return nil, log.Errorf("error parsing line: %q: %w", line, err) } partitions = append(partitions, p) } return partitions, scanner.Err() }