summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doGui.go40
-rw-r--r--hasPartitionTable.go34
-rw-r--r--isDriveInUse.go95
3 files changed, 164 insertions, 5 deletions
diff --git a/doGui.go b/doGui.go
index 9a902ee..8263587 100644
--- a/doGui.go
+++ b/doGui.go
@@ -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()
diff --git a/hasPartitionTable.go b/hasPartitionTable.go
new file mode 100644
index 0000000..96ed786
--- /dev/null
+++ b/hasPartitionTable.go
@@ -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
+}
diff --git a/isDriveInUse.go b/isDriveInUse.go
new file mode 100644
index 0000000..912ae07
--- /dev/null
+++ b/isDriveInUse.go
@@ -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
+}