package main import ( "bufio" "os" "path/filepath" "strings" "go.wit.com/log" ) func isBlockDeviceInUse(dev string) bool { base := filepath.Base(dev) // 1. Check /proc/mounts if isMounted(dev, base) { log.Info(dev, "dev is mounted (/proc/mounts)") return true } // 2. Check /proc/swaps if isSwap(dev) { log.Info(dev, "dev is used by swap (/proc/swaps)") return true } // 3. Check /proc/mdstat for RAID if isInRAID(base) { log.Info(dev, "dev is in software raid (/proc/mdstat)") return true } // 4. Check sysfs for device-mapper or LVM use if hasDMHolders(base) { log.Info(dev, "dev has lvm partitions") return true } log.Info(dev, "dev appears to be unused") return false } func isMounted(dev, base string) bool { f, err := os.Open("/proc/mounts") if err != nil { return false } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { if strings.HasPrefix(scanner.Text(), dev) || strings.Contains(scanner.Text(), base) { return true } } return false } func isSwap(dev string) bool { f, err := os.Open("/proc/swaps") if err != nil { return false } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { if strings.HasPrefix(scanner.Text(), dev) { return true } } return false } func isInRAID(base string) bool { f, err := os.Open("/proc/mdstat") if err != nil { return false } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { if strings.Contains(scanner.Text(), base) { return true } } return false } func hasDMHolders(base string) bool { path := filepath.Join("/sys/block", base, "holders") entries, err := os.ReadDir(path) return err == nil && len(entries) > 0 }