more sanity checks

This commit is contained in:
Jeff Carr 2025-08-17 17:43:34 -05:00
parent 25c604aeee
commit 145244f63d
3 changed files with 164 additions and 5 deletions

View File

@ -6,7 +6,6 @@ package main
// An app to submit patches for the 30 GO GUI repos
import (
"fmt"
"os"
"strings"
"time"
@ -21,7 +20,7 @@ import (
func debug() {
for {
time.Sleep(10 * time.Second)
log.Info("TODO: use this debug loop for something?")
// log.Info("TODO: use this debug loop for something?")
}
}
@ -40,17 +39,48 @@ func addDrive(devname string, displayDesc string) *Block {
}
func switchDrive(blk *Block) {
var inUse bool = false
me.currentDev = blk
me.parted.SetText("Partition " + blk.Name)
if isBlockDeviceInUse(blk.Name) {
log.Info("Is in use?", blk.Name)
me.parted.SetText("Partition " + blk.Name + " (in use)")
me.parted.Disable()
inUse = true
} else {
log.Info("Is probably not in use?", blk.Name)
me.parted.SetText("Partition " + blk.Name + " as gpt boot disk")
me.parted.Enable()
}
log.Info("check if", me.currentDev.Name, "is in use")
result, err := shell.RunVerbose([]string{"parted", me.currentDev.Name, "print"})
log.Info("result =", result.Stdout, "err =", err)
out := strings.Join(result.Stdout, "\n")
if err != nil {
out += fmt.Sprintf("err = %v", err)
out += log.Sprintf("err = %v", err)
}
me.driveInfoBox.SetText(out)
if inUse {
// if the drive is in use already, you can just stop here
return
}
if ok, err := hasPartitionTable(blk.Name); err != nil {
out := log.Sprintf("Error checking partition table: %s\n", err)
log.Warn(out)
me.parted.Disable()
me.driveInfoBox.SetText(out)
} else {
if !ok {
log.Printf("%s has no partition table safe for gdisk\n", blk.Name)
} else {
log.Printf("%s already has a partition table\n", blk.Name)
me.parted.SetText("Partition " + blk.Name + " (has partitions)")
me.parted.Disable()
}
}
}
func doGui() {
@ -95,7 +125,7 @@ func drawWindow(win *gadgets.GenericWindow) {
log.Info("You must select a drive first")
return
}
log.Info("TODO: figure out if the drive is in use")
log.Info("If you got here, gdisk should be safe to run on", me.currentDev.Name)
})
grid.NextRow()

34
hasPartitionTable.go Normal file
View File

@ -0,0 +1,34 @@
package main
import (
"bytes"
"fmt"
"os/exec"
"strings"
)
// HasPartitionTable runs `parted <device> print` and returns:
// - true if the disk has a recognized partition table
// - false if it's unrecognized or empty
func hasPartitionTable(dev string) (bool, error) {
cmd := exec.Command("parted", "-s", dev, "print")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err := cmd.Run()
output := out.String()
// Check for known "no label" pattern
if strings.Contains(output, "unrecognised disk label") ||
strings.Contains(output, "unrecognized disk label") ||
strings.Contains(output, "Error") {
return false, nil
}
if err != nil {
return false, fmt.Errorf("parted failed: %w: %s", err, output)
}
return true, nil
}

95
isDriveInUse.go Normal file
View File

@ -0,0 +1,95 @@
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
}