Compare commits
5 Commits
edb3e23311
...
189668553d
Author | SHA1 | Date |
---|---|---|
|
189668553d | |
|
25f0ec7e26 | |
|
145244f63d | |
|
25c604aeee | |
|
bd5b16d875 |
|
@ -2,4 +2,6 @@
|
||||||
go.mod
|
go.mod
|
||||||
go.sum
|
go.sum
|
||||||
fixup
|
fixup
|
||||||
|
*.so
|
||||||
|
*pb.go
|
||||||
/files/*
|
/files/*
|
||||||
|
|
45
Makefile
45
Makefile
|
@ -2,16 +2,15 @@ VERSION = $(shell git describe --tags)
|
||||||
GUIVERSION = $(shell git describe --tags)
|
GUIVERSION = $(shell git describe --tags)
|
||||||
BUILDTIME = $(shell date +%Y.%m.%d)
|
BUILDTIME = $(shell date +%Y.%m.%d)
|
||||||
|
|
||||||
all: verbose
|
all: block.pb.go verbose
|
||||||
-fixup --gui-check-plugin ../../../toolkits/gocui/gocui.so
|
# -fixup --gui-check-plugin ../../../toolkits/gocui/gocui.so
|
||||||
fixup --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so drives
|
fixup --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so
|
||||||
|
|
||||||
go-build: goimports
|
go-build: goimports
|
||||||
GO111MODULE=off go build \
|
GO111MODULE=off go build \
|
||||||
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
|
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
|
||||||
|
|
||||||
verbose: goimports
|
verbose: goimports
|
||||||
-cp -a ../../../toolkits/gocui/gocui.so resources/
|
|
||||||
GO111MODULE=off go install -v -x \
|
GO111MODULE=off go install -v -x \
|
||||||
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
|
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
|
||||||
|
|
||||||
|
@ -22,9 +21,9 @@ install: goimports
|
||||||
vet:
|
vet:
|
||||||
GO111MODULE=off go vet
|
GO111MODULE=off go vet
|
||||||
|
|
||||||
stderr: go-build
|
stderr: verbose
|
||||||
echo "writing to /tmp/wit-test.log"
|
echo "writing to /tmp/fixup.log"
|
||||||
./wit-test >/tmp/wit-test.log 2>&1
|
fixup --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so drives >/tmp/fixup.log 2>&1
|
||||||
|
|
||||||
goimports:
|
goimports:
|
||||||
goimports -w *.go
|
goimports -w *.go
|
||||||
|
@ -33,6 +32,8 @@ goimports:
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f go.*
|
rm -f go.*
|
||||||
|
rm -f *.pb.go
|
||||||
|
go-mod-clean purge
|
||||||
|
|
||||||
gpl:
|
gpl:
|
||||||
wit-test --witcom
|
wit-test --witcom
|
||||||
|
@ -40,29 +41,11 @@ gpl:
|
||||||
check-git-clean:
|
check-git-clean:
|
||||||
@git diff-index --quiet HEAD -- || (echo "Git repository is dirty, please commit your changes first"; exit 1)
|
@git diff-index --quiet HEAD -- || (echo "Git repository is dirty, please commit your changes first"; exit 1)
|
||||||
|
|
||||||
old-debian-release: install
|
block.pb.go: block.proto
|
||||||
wit-test debian --dry-run --verbose --release
|
autogenpb --proto block.proto
|
||||||
|
|
||||||
debian-release: install
|
commit:
|
||||||
forge dirty
|
FORGE_URL="https://forge.grid.wit.com/" forge commit --all
|
||||||
rm -f ~/incoming/*.deb
|
|
||||||
rm -f ~/go/lib/go-gui/*
|
|
||||||
forge --install go.wit.com/apps/go-deb
|
|
||||||
go-deb -h # check to make sure go-deb builds
|
|
||||||
wit-test debian --verbose
|
|
||||||
ls -hl ~/incoming/
|
|
||||||
do-aptly
|
|
||||||
|
|
||||||
debian-release-force: install
|
submit:
|
||||||
forge dirty
|
FORGE_URL="https://forge.grid.wit.com/" forge patch --submit "forge auto commit"
|
||||||
rm -f ~/incoming/*.deb
|
|
||||||
rm -f ~/go/lib/go-gui/*
|
|
||||||
forge --install go.wit.com/apps/go-deb
|
|
||||||
go-deb -h # check to make sure go-deb builds
|
|
||||||
wit-test debian --force --verbose
|
|
||||||
ls -hl ~/incoming/
|
|
||||||
-dpkg-deb -c ~/incoming/go-gui-toolkits*.deb
|
|
||||||
do-aptly
|
|
||||||
|
|
||||||
debian-release-build-only: install
|
|
||||||
wit-test debian --verbose --release
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package main;
|
||||||
|
|
||||||
|
message Block {
|
||||||
|
string name = 1; // `autogenpb:sort` `autogenpb:unique`
|
||||||
|
uint32 major = 2;
|
||||||
|
uint32 minor = 3;
|
||||||
|
uint64 size_bytes = 4;
|
||||||
|
bool removable = 5;
|
||||||
|
bool read_only = 6;
|
||||||
|
string type = 7; // e.g., "disk", "part", "rom", "loop"
|
||||||
|
repeated string mountpoints = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Blocks { // `autogenpb:marshal` `autogenpb:mutex`
|
||||||
|
string uuid = 1; // `autogenpb:uuid:abe10848-cf2b-4440-b5a8-0aaa2ce50aad`
|
||||||
|
string version = 2; // `autogenpb:version:v0.0.1`
|
||||||
|
repeated Block Blocks = 3; // THIS MUST BE Block and then Blocks
|
||||||
|
}
|
11
doDrives.go
11
doDrives.go
|
@ -17,7 +17,11 @@ func doDrives() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range parts {
|
for _, p := range parts {
|
||||||
log.Printf("Device: /dev/%s\tSize: %d KiB\n", p.Name, p.Blocks)
|
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"
|
blockDir := "/sys/block"
|
||||||
|
@ -44,11 +48,12 @@ func doDrives() {
|
||||||
used := false
|
used := false
|
||||||
for _, part := range partitions {
|
for _, part := range partitions {
|
||||||
partName := filepath.Base(part)
|
partName := filepath.Base(part)
|
||||||
|
partDev := "/dev/" + partName
|
||||||
if partName == dev {
|
if partName == dev {
|
||||||
|
log.Printf(" SKIP MAIN Partition: %s\n", partDev)
|
||||||
continue // skip the main device
|
continue // skip the main device
|
||||||
}
|
}
|
||||||
hasPartition = true
|
hasPartition = true
|
||||||
partDev := "/dev/" + partName
|
|
||||||
isMounted := mounts[partDev]
|
isMounted := mounts[partDev]
|
||||||
log.Printf(" Partition: %s [%v]\n", partDev, isMounted)
|
log.Printf(" Partition: %s [%v]\n", partDev, isMounted)
|
||||||
if isMounted {
|
if isMounted {
|
||||||
|
@ -61,7 +66,7 @@ func doDrives() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !used {
|
if !used {
|
||||||
log.Println(" → Drive appears to be unused.")
|
log.Println(" * Drive appears to be unused.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
131
doGui.go
131
doGui.go
|
@ -7,17 +7,95 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.wit.com/gui"
|
"go.wit.com/gui"
|
||||||
"go.wit.com/lib/gadgets"
|
"go.wit.com/lib/gadgets"
|
||||||
|
"go.wit.com/lib/gui/shell"
|
||||||
|
"go.wit.com/lib/protobuf/virtpb"
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func debug() {
|
func debug() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
log.Info("TODO: use this?")
|
// log.Info("TODO: use this debug loop for something?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adds a new drive to the dropdown menu and protobuf
|
||||||
|
func addDrive(devname string, displayDesc string) *Block {
|
||||||
|
if blkpb := me.pb.FindByName(devname); blkpb != nil {
|
||||||
|
return blkpb
|
||||||
|
}
|
||||||
|
|
||||||
|
s := log.Sprintf("%-12s %-8s", devname, displayDesc)
|
||||||
|
log.Info(s)
|
||||||
|
me.dd.AddText(s)
|
||||||
|
|
||||||
|
blkpb := me.pb.InsertByName(devname)
|
||||||
|
return blkpb
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the output of parted <dev> print
|
||||||
|
func showPartitions(blk *Block) {
|
||||||
|
if blk == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("check if", blk.Name, "is in use")
|
||||||
|
result, err := shell.RunVerbose([]string{"parted", blk.Name, "print"})
|
||||||
|
log.Info("result =", result.Stdout, "err =", err)
|
||||||
|
out := strings.Join(result.Stdout, "\n")
|
||||||
|
if err != nil {
|
||||||
|
out += log.Sprintf("err = %v", err)
|
||||||
|
}
|
||||||
|
me.driveInfoBox.SetText(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func switchDrive(blk *Block) {
|
||||||
|
var inUse bool = false
|
||||||
|
me.currentDev = blk
|
||||||
|
|
||||||
|
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 += 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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,31 +119,52 @@ func doGui() {
|
||||||
func drawWindow(win *gadgets.GenericWindow) {
|
func drawWindow(win *gadgets.GenericWindow) {
|
||||||
grid := win.Group.RawGrid()
|
grid := win.Group.RawGrid()
|
||||||
|
|
||||||
grid.NewLabel("Drives:")
|
|
||||||
|
|
||||||
me.dd = grid.NewDropdown()
|
me.dd = grid.NewDropdown()
|
||||||
me.dd.AddText("/dev/blah")
|
// me.dd.AddText("/dev/blah")
|
||||||
me.dd.Custom = func() {
|
me.dd.Custom = func() {
|
||||||
log.Info("todo: changed drive")
|
fields := strings.Fields(me.dd.String())
|
||||||
|
log.Info("changed to", fields)
|
||||||
|
if len(fields) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if blkpb := me.pb.FindByName(fields[0]); blkpb != nil {
|
||||||
|
switchDrive(blkpb)
|
||||||
|
} else {
|
||||||
|
log.Info("couldn't find in protobuf:", fields)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
grid.NextRow()
|
grid.NextRow()
|
||||||
|
|
||||||
|
// a button to format or blank a drive
|
||||||
|
me.parted = grid.NewButton("select drive", func() {
|
||||||
|
if me.currentDev == nil {
|
||||||
|
log.Info("You must select a drive first")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Info("If you got here, gdisk should be safe to run on", me.currentDev.Name)
|
||||||
|
if err := makeDefaultGPT(me.currentDev.Name); err != nil {
|
||||||
|
log.Info("PARTITIONING FAILED on", me.currentDev.Name, "with", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showPartitions(me.currentDev)
|
||||||
|
})
|
||||||
|
|
||||||
|
grid.NextRow()
|
||||||
|
|
||||||
grid.NewButton("doDrives()", func() {
|
grid.NewButton("doDrives()", func() {
|
||||||
doDrives()
|
doDrives()
|
||||||
})
|
})
|
||||||
|
|
||||||
grid.NewButton("doDrives2()", func() {
|
grid.NewButton("show blkpb", func() {
|
||||||
doDrives2()
|
for blk := range me.pb.IterAll() {
|
||||||
|
log.Printf("found %-12s %s\n", blk.Name, virtpb.HumanFormatBytes(int64(blk.SizeBytes)))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
grid.NewButton("partition drives", func() {
|
|
||||||
log.Info("something")
|
|
||||||
})
|
|
||||||
|
|
||||||
grid.NextRow()
|
grid.NextRow()
|
||||||
|
|
||||||
grid.NewButton("ConfigSave()", func() {
|
grid = win.Middle.RawGrid()
|
||||||
log.Info("todo: make code for this")
|
me.driveInfoBox = grid.NewLabel("<drive info>")
|
||||||
})
|
|
||||||
|
|
||||||
|
doDrives2()
|
||||||
|
doDrives()
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,7 @@ func doDrives2() {
|
||||||
for _, info := range devs {
|
for _, info := range devs {
|
||||||
devPath := "/dev/" + info.Name
|
devPath := "/dev/" + info.Name
|
||||||
if info.IsRaw {
|
if info.IsRaw {
|
||||||
s := log.Sprintf("%-12s -> %-8s (raw)", devPath, info.Type)
|
addDrive(devPath, log.Sprintf("-> %-8s (raw)", info.Type))
|
||||||
log.Info(s)
|
|
||||||
me.dd.AddText(s)
|
|
||||||
} else {
|
} else {
|
||||||
if info.Parent != "" {
|
if info.Parent != "" {
|
||||||
log.Printf("%-12s -> partition of /dev/%s\n", devPath, info.Parent)
|
log.Printf("%-12s -> partition of /dev/%s\n", devPath, info.Parent)
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
21
main.go
21
main.go
|
@ -6,7 +6,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"debug/buildinfo"
|
"debug/buildinfo"
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -33,6 +32,14 @@ func main() {
|
||||||
gui.InitArg()
|
gui.InitArg()
|
||||||
me.pp = arg.MustParse(&argv)
|
me.pp = arg.MustParse(&argv)
|
||||||
|
|
||||||
|
// check if the binary is being called to test
|
||||||
|
// if the plugin can actually loaded. This is a hack
|
||||||
|
// around needing a Test() plugin load function in GO
|
||||||
|
if gui.IsGoPluginTestHack() {
|
||||||
|
gui.CheckPlugin()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
if argv.Bash {
|
if argv.Bash {
|
||||||
argv.doBash()
|
argv.doBash()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
@ -42,8 +49,7 @@ func main() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPlug("../../../toolkits/gocui/gocui.so")
|
me.pb = NewBlocks()
|
||||||
// checkPlug("/usr/lib/go-gui-toolkits/gocui.v0.22.46.so")
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if argv.Drives != nil {
|
if argv.Drives != nil {
|
||||||
|
@ -52,9 +58,6 @@ func main() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// doDrives()
|
|
||||||
// okExit("everything compiled")
|
|
||||||
|
|
||||||
go listenForBlockEvents()
|
go listenForBlockEvents()
|
||||||
doGui()
|
doGui()
|
||||||
okExit("everything compiled")
|
okExit("everything compiled")
|
||||||
|
@ -117,7 +120,7 @@ func dumpDebug() {
|
||||||
|
|
||||||
func checkPlug(pluginPath string) *plugin.Plugin {
|
func checkPlug(pluginPath string) *plugin.Plugin {
|
||||||
if err := checkPluginViaSubprocess(pluginPath); err != nil {
|
if err := checkPluginViaSubprocess(pluginPath); err != nil {
|
||||||
fmt.Printf("Plugin check failed: %v\n", err)
|
log.Printf("Plugin check failed: %v\n", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,11 +136,11 @@ func checkPlug(pluginPath string) *plugin.Plugin {
|
||||||
func checkPluginViaSubprocess(path string) error {
|
func checkPluginViaSubprocess(path string) error {
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get executable path: %w", err)
|
return log.Errorf("failed to get executable path: %w", err)
|
||||||
}
|
}
|
||||||
resolved, err := filepath.EvalSymlinks(exe)
|
resolved, err := filepath.EvalSymlinks(exe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to resolve executable symlink: %w", err)
|
return log.Errorf("failed to resolve executable symlink: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(resolved, "--gui-check-plugin", path)
|
cmd := exec.Command(resolved, "--gui-check-plugin", path)
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"go.wit.com/log"
|
||||||
|
|
||||||
|
"github.com/diskfs/go-diskfs"
|
||||||
|
"github.com/diskfs/go-diskfs/partition/gpt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// make a default bootable GPT partition table
|
||||||
|
func makeDefaultGPT(devname string) error {
|
||||||
|
// Open disk
|
||||||
|
// disk, err := diskfs.Open(devname, diskfs.ReadWrite)
|
||||||
|
disk, err := diskfs.Open(devname, diskfs.WithOpenMode(diskfs.ReadWrite))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to open disk: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(devname)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to open file for size: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Determine disk size via Seek
|
||||||
|
sizeBytes, err := file.Seek(0, io.SeekEnd)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to determine disk size: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sectorSize := int64(512)
|
||||||
|
totalSectors := uint64(sizeBytes / sectorSize)
|
||||||
|
|
||||||
|
// Setup partitions:
|
||||||
|
// Partition 1: BIOS boot, ~1MiB, starts at sector 2048
|
||||||
|
biosStart := uint64(2048)
|
||||||
|
biosSize := uint64(1 * 1024 * 1024) // bytes
|
||||||
|
biosSectors := biosSize / uint64(sectorSize)
|
||||||
|
|
||||||
|
// Partition 2: rest of the disk
|
||||||
|
rootStart := biosStart + biosSectors
|
||||||
|
rootSectors := totalSectors - rootStart
|
||||||
|
|
||||||
|
table := &gpt.Table{
|
||||||
|
LogicalSectorSize: int(sectorSize),
|
||||||
|
PhysicalSectorSize: int(sectorSize),
|
||||||
|
ProtectiveMBR: true,
|
||||||
|
Partitions: []*gpt.Partition{
|
||||||
|
{
|
||||||
|
Start: biosStart,
|
||||||
|
End: biosStart + biosSectors - 1,
|
||||||
|
// Size is optional, but let's provide it
|
||||||
|
Size: biosSectors * uint64(sectorSize),
|
||||||
|
// GUID for BIOS boot partition (ESP-like GUID for BIOS boot)
|
||||||
|
Type: biosBootGUID,
|
||||||
|
Name: "bios_grub",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Start: rootStart,
|
||||||
|
End: totalSectors - 1,
|
||||||
|
Size: rootSectors * uint64(sectorSize),
|
||||||
|
// GUID for Linux filesystem partition
|
||||||
|
Type: linuxFSGUID,
|
||||||
|
Name: "root",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := disk.Partition(table); err != nil {
|
||||||
|
log.Errorf("Failed to write GPT partition table: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Partition table successfully written!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GUID definitions (copied from GPT standard tables)
|
||||||
|
const (
|
||||||
|
biosBootGUID = "21686148-6449-6E6F-744E-656564454649" // BIOS boot
|
||||||
|
linuxFSGUID = "0FC63DAF-8483-4772-8E79-3D69D8477DE4" // Linux filesystem
|
||||||
|
)
|
|
@ -1,47 +0,0 @@
|
||||||
package plugincheck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"debug/buildinfo"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CheckPluginCompatibility verifies that the plugin .so file was built
|
|
||||||
// with the same Go version and dependency versions as the host binary.
|
|
||||||
func CheckPluginCompatibility(pluginPath string) error {
|
|
||||||
pluginInfo, err := buildinfo.ReadFile(pluginPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read plugin build info: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mainInfo, ok := debug.ReadBuildInfo()
|
|
||||||
if !ok {
|
|
||||||
return errors.New("failed to read main binary build info")
|
|
||||||
}
|
|
||||||
|
|
||||||
if pluginInfo.GoVersion != mainInfo.GoVersion {
|
|
||||||
return fmt.Errorf("Go version mismatch: plugin=%s, host=%s",
|
|
||||||
pluginInfo.GoVersion, mainInfo.GoVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a map of main binary dependencies for quick lookup
|
|
||||||
hostDeps := make(map[string]string)
|
|
||||||
for _, dep := range mainInfo.Deps {
|
|
||||||
hostDeps[dep.Path] = dep.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare plugin dependencies
|
|
||||||
for _, dep := range pluginInfo.Deps {
|
|
||||||
hostVer, ok := hostDeps[dep.Path]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("dependency %s not found in host binary", dep.Path)
|
|
||||||
}
|
|
||||||
if dep.Version != hostVer {
|
|
||||||
return fmt.Errorf("dependency version mismatch for %s: plugin=%s, host=%s",
|
|
||||||
dep.Path, dep.Version, hostVer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
Binary file not shown.
10
structs.go
10
structs.go
|
@ -12,7 +12,11 @@ var me *autoType
|
||||||
|
|
||||||
// this app's variables
|
// this app's variables
|
||||||
type autoType struct {
|
type autoType struct {
|
||||||
pp *arg.Parser // go-arg preprocessor
|
pp *arg.Parser // go-arg preprocessor
|
||||||
myGui *gui.Node // the gui toolkit handle
|
myGui *gui.Node // the gui toolkit handle
|
||||||
dd *gui.Node // the drives dropdown list
|
dd *gui.Node // the drives dropdown list
|
||||||
|
parted *gui.Node // the current drive to run parted on
|
||||||
|
currentDev *Block // the current dev entry to work on
|
||||||
|
pb *Blocks // the block dev protobuf
|
||||||
|
driveInfoBox *gui.Node // displays the drive info
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -43,7 +44,11 @@ func listenForBlockEvents() {
|
||||||
msg := parseUevent(buf[:n])
|
msg := parseUevent(buf[:n])
|
||||||
if msg["SUBSYSTEM"] == "block" && msg["ACTION"] == "add" {
|
if msg["SUBSYSTEM"] == "block" && msg["ACTION"] == "add" {
|
||||||
log.Printf("New block device added: %s\n", msg["DEVNAME"])
|
log.Printf("New block device added: %s\n", msg["DEVNAME"])
|
||||||
|
devname := "/dev/" + msg["DEVNAME"]
|
||||||
|
me.dd.AddText(devname + " new")
|
||||||
|
me.pb.InsertByName(devname)
|
||||||
}
|
}
|
||||||
|
log.Printf("New syscall.NETLINK_KOBJECT_UEVENT: %v\n", msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue