1
0
mirror of https://github.com/byReqz/go-etcher.git synced 2025-07-03 03:20:49 +00:00

7 Commits

Author SHA1 Message Date
947660b773 add output verification 2022-02-08 12:28:49 +01:00
15b7e2f781 add headline to device overview 2022-02-07 13:03:38 +01:00
30afa9ae21 make force flag actually do something 2022-02-07 12:44:07 +01:00
e9ac06c8cf remove clutter 2022-02-07 12:36:08 +01:00
95f4d1d682 fix blockdevices being unwritable 2022-02-07 12:21:51 +01:00
4dfdda9e78 fix issue with size warning 2022-01-31 22:34:30 +01:00
36abb0e312 show possible target devices 2022-01-26 23:40:45 +01:00
2 changed files with 103 additions and 39 deletions

View File

@ -12,6 +12,7 @@ arguments:
-d, --device string target device -d, --device string target device
-f, --force override safety features -f, --force override safety features
-i, --input string input file -i, --input string input file
-n, --no-hash disable hash verification
``` ```
If no image or device is specified, etcher will enter interactive mode and prompt for the missing parameters. If no image or device is specified, etcher will enter interactive mode and prompt for the missing parameters.

141
main.go
View File

@ -6,6 +6,9 @@ import (
"time" "time"
"log" "log"
"strings" "strings"
"runtime"
"strconv"
"crypto/sha256"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/briandowns/spinner" "github.com/briandowns/spinner"
@ -16,11 +19,13 @@ import (
var device string var device string
var input string var input string
var force bool var force bool
var disable_hash bool
func init() { func init() {
flag.StringVarP(&device, "device", "d", "", "target device") flag.StringVarP(&device, "device", "d", "", "target device")
flag.StringVarP(&input, "input", "i", "", "input file") flag.StringVarP(&input, "input", "i", "", "input file")
flag.BoolVarP(&force, "force", "f", false, "override safety features") flag.BoolVarP(&force, "force", "f", false, "override safety features")
flag.BoolVarP(&disable_hash, "no-hash", "n", false, "disable hash verification")
flag.Parse() flag.Parse()
} }
@ -45,6 +50,7 @@ func GetPath() string {
} }
func GetDest() string { func GetDest() string {
PrintAvail()
dest, err := ac.Read("[ " + color.YellowString("i") + " ] Please input destination: ") dest, err := ac.Read("[ " + color.YellowString("i") + " ] Please input destination: ")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -85,24 +91,42 @@ func WriteImage(image *os.File, target *os.File, size int64) (int64, error) {
return written, err return written, err
} }
func Sync(image *os.File, target *os.File) error { func PrintAvail() {
err := image.Sync() if runtime.GOOS == "linux" {
if err != nil { block, _ := os.ReadDir("/sys/block")
return err if len(block) == 0 {
return
}
var targets []string
for _, device := range block {
if strings.HasPrefix(device.Name(), "sd") {
targets = append(targets, device.Name())
}
if strings.HasPrefix(device.Name(), "nvme") {
targets = append(targets, device.Name())
}
if strings.HasPrefix(device.Name(), "vd") {
targets = append(targets, device.Name())
}
}
fmt.Println("Available devices:")
for _, target := range targets {
sizefile, _ := os.Open("/sys/block/" + target + "/size")
sizeread, _ := io.ReadAll(sizefile)
_ = sizefile.Close()
sizestring := strings.ReplaceAll(string(sizeread), "\n", "")
size, _ := strconv.Atoi(sizestring)
size = size * 512
size = size / 1024 / 1024 / 1024
fmt.Print(" * ", "/dev/" + target)
if size > 0 {
fmt.Print(" [", size, "GB]\n")
} else {
fmt.Println("")
}
}
} }
err = target.Sync()
if err != nil {
return err
}
err = image.Close()
if err != nil {
return err
}
err = target.Close()
if err != nil {
return err
}
return nil
} }
func main() { func main() {
@ -142,18 +166,11 @@ func main() {
s.Stop() s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Getting file details ") fmt.Println("\r[", color.RedString("✘"), "] Getting file details ")
log.Fatal(err) log.Fatal(err)
} else {
s.Stop()
fmt.Println("\r[", color.GreenString("✓"), "] Getting file details ")
} }
s.Prefix = "[ "
s.Suffix = " ] Opening files"
s.Start()
image, err := os.Open(input) image, err := os.Open(input)
if err != nil { if err != nil {
s.Stop() s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Opening files ") fmt.Println("\r[", color.RedString("✘"), "] Getting file details ")
log.Fatal(err) log.Fatal(err)
} }
var inputsize int64 var inputsize int64
@ -164,11 +181,12 @@ func main() {
} else { } else {
inputsize, err = image.Seek(0, io.SeekEnd) inputsize, err = image.Seek(0, io.SeekEnd)
inputisblock = true inputisblock = true
_, _ = image.Seek(0, 0)
} }
target, err := os.OpenFile(device, os.O_RDWR, 0660) target, err := os.OpenFile(device, os.O_RDWR, 0660)
if err != nil { if err != nil {
s.Stop() s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Opening files ") fmt.Println("\r[", color.RedString("✘"), "] Getting file details ")
log.Fatal(err) log.Fatal(err)
} }
var targetsize int64 var targetsize int64
@ -179,14 +197,26 @@ func main() {
} else { } else {
targetsize, err = target.Seek(0, io.SeekEnd) targetsize, err = target.Seek(0, io.SeekEnd)
targetisblock = true targetisblock = true
_, _ = target.Seek(0, 0)
}
prehash := sha256.New()
if ! (force || disable_hash) {
if err != nil {
s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Getting file details ")
log.Fatal(err)
}
_, err = io.Copy(prehash, image)
_, _ = image.Seek(0, 0)
} }
if err != nil { if err != nil {
s.Stop() s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Opening files ") fmt.Println("\r[", color.RedString("✘"), "] Getting file details ")
log.Fatal(err) log.Fatal(err)
} else { } else {
s.Stop() s.Stop()
fmt.Println("\r[", color.GreenString("✓"), "] Opening files ") fmt.Println("\r[", color.GreenString("✓"), "] Getting file details ")
} }
inputmb := fmt.Sprint("[", inputsize / 1024 / 1024, "MB]") inputmb := fmt.Sprint("[", inputsize / 1024 / 1024, "MB]")
devicemb := fmt.Sprint("[", targetsize / 1024 / 1024, "MB]") devicemb := fmt.Sprint("[", targetsize / 1024 / 1024, "MB]")
@ -204,18 +234,20 @@ func main() {
} }
fmt.Println("[", color.BlueString("i"), "] Input device/file: " + input, inputmb, inputblock) fmt.Println("[", color.BlueString("i"), "] Input device/file: " + input, inputmb, inputblock)
fmt.Println("[", color.BlueString("i"), "] Output device/file: " + device, devicemb, targetblock) fmt.Println("[", color.BlueString("i"), "] Output device/file: " + device, devicemb, targetblock)
if statinput.Size() > statdevice.Size() { if force == false {
fmt.Println("[", color.RedString("w"), "]", color.RedString(" Warning:"), "Input file seems to be bigger than the destination!") if inputsize > targetsize {
fmt.Println("[", color.RedString("w"), "]", color.RedString(" Warning:"), "Input file seems to be bigger than the destination!")
}
fmt.Print(color.HiWhiteString("Do you want to continue? [y/N]: "))
var yesno string
_, _ = fmt.Scanln(&yesno)
yesno = strings.TrimSpace(yesno)
if ! (yesno == "y" || yesno == "Y") {
log.Fatal("aborted")
}
} }
fmt.Print(color.HiWhiteString("Do you want to continue? [y/N]: "))
var yesno string
_, _ = fmt.Scanln(&yesno)
yesno = strings.TrimSpace(yesno)
if ! (yesno == "y" || yesno == "Y") {
log.Fatal("aborted")
}
written, err := WriteImage(image, target, inputsize) written, err := WriteImage(image, target, inputsize)
_, _ = target.Seek(0, 0)
if err != nil { if err != nil {
fmt.Println("\r[", color.RedString("✘"), "] Writing image,", written, "bytes written ") fmt.Println("\r[", color.RedString("✘"), "] Writing image,", written, "bytes written ")
log.Fatal(err) log.Fatal(err)
@ -226,7 +258,13 @@ func main() {
s.Prefix = "[ " s.Prefix = "[ "
s.Suffix = " ] Syncing" s.Suffix = " ] Syncing"
s.Start() s.Start()
err = Sync(image, target) err = image.Sync()
if err != nil {
s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Syncing ")
log.Fatal(err)
}
err = target.Sync()
if err != nil { if err != nil {
s.Stop() s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Syncing ") fmt.Println("\r[", color.RedString("✘"), "] Syncing ")
@ -235,4 +273,29 @@ func main() {
s.Stop() s.Stop()
fmt.Println("\r[", color.GreenString("✓"), "] Syncing ") fmt.Println("\r[", color.GreenString("✓"), "] Syncing ")
} }
if ! (force || disable_hash) {
s.Prefix = "[ "
s.Suffix = " ] Verifying"
s.Start()
posthash := sha256.New()
_, err = io.CopyN(posthash, target, inputsize)
presum := fmt.Sprintf("%x", prehash.Sum(nil))
postsum := fmt.Sprintf("%x", posthash.Sum(nil))
if err != nil || presum != postsum {
s.Stop()
fmt.Println("\r[", color.RedString("✘"), "] Verifying ")
log.Fatal(err)
} else {
s.Stop()
fmt.Println("\r[", color.GreenString("✓"), "] Verifying ")
}
}
err = image.Close()
if err != nil {
log.Fatal(err)
}
err = target.Close()
if err != nil {
log.Fatal(err)
}
} }