Browse Source

Add format tool

content-update
xpetit 3 years ago
parent
commit
4704219c54
No known key found for this signature in database
GPG Key ID: 97C60669182C17A5
  1. 4
      sh/debian/ubuntu/configure.sh
  2. 5
      sh/debian/ubuntu/system/usr/local/src/format/go.mod
  3. 4
      sh/debian/ubuntu/system/usr/local/src/format/go.sum
  4. 239
      sh/debian/ubuntu/system/usr/local/src/format/main.go

4
sh/debian/ubuntu/configure.sh diff.vendored

@ -434,6 +434,10 @@ cd /tmp/system
cp --preserve=mode -RT . /
cd /usr/local/src/format
sudo -iu student go mod download
sudo -iu student go build -o /usr/local/bin/format
cd "$script_dir"
rm -rf /tmp/system

5
sh/debian/ubuntu/system/usr/local/src/format/go.mod diff.vendored

@ -0,0 +1,5 @@
module main
go 1.16
require github.com/olekukonko/tablewriter v0.0.5

4
sh/debian/ubuntu/system/usr/local/src/format/go.sum diff.vendored

@ -0,0 +1,4 @@
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=

239
sh/debian/ubuntu/system/usr/local/src/format/main.go diff.vendored

@ -0,0 +1,239 @@
package main
import (
"encoding/json"
"errors"
"fmt"
"math"
"os"
"os/exec"
"strconv"
"strings"
"github.com/olekukonko/tablewriter"
)
func fatalln(a ...interface{}) {
fmt.Println(a...)
os.Exit(1)
}
func expect(target, err error, action string) {
if err != nil && err != target && !errors.Is(err, target) {
fatalln("Failed to", action, ":", err)
}
}
func renderTable(data [][]string) {
table := tablewriter.NewWriter(os.Stdout)
table.SetColumnSeparator(" ")
table.SetCenterSeparator(" ")
table.SetRowSeparator(" ")
table.SetAlignment(tablewriter.ALIGN_CENTER)
table.SetHeader(data[0])
for _, row := range data[1:] {
table.Append(row)
}
table.Render()
}
// run returns the output of the command
// In case of error, display the action intended, the command and the error
func run(action, name string, arg ...string) []byte {
b, err := exec.Command(name, arg...).CombinedOutput()
if err != nil {
fmt.Println("Failed to", action)
fmt.Printf("%s %#v\n", name, arg)
if _, ok := err.(*exec.ExitError); ok {
fatalln(string(b))
}
fatalln(err)
}
return b
}
type (
size int
stringTrim string
device struct {
Path string // path to the device node
RO bool // read-only device
RM bool // removable device
Hotplug bool // removable or hotplug device (usb, pcmcia, ...)
Model stringTrim // device identifier
Size size // size of the device
Type string // device type
Tran string // device transport type
Vendor stringTrim // device vendor
}
)
func (s stringTrim) String() string {
return strings.TrimSpace(string(s))
}
// format size with SI prefix
func (s size) String() string {
f := float64(s)
if f < 0 {
f = 0
}
unit := " kMGTPEZY"
for f >= 1000 {
unit = unit[1:]
f /= 1000
}
var prec int
if unit[0] != ' ' && math.Round(f) < 10 {
prec = 1
}
return fmt.Sprintf("%.*f %cB", prec, f, unit[0])
}
func main() {
// Usage
fmt.Println("While using this formatting tool:")
fmt.Println(" - do not plug/unplug any drive")
fmt.Println(" - make sure the drive is not in use")
fmt.Print("Press ENTER to continue")
fmt.Scanln()
// Get a list of the block devices
var data struct {
Blockdevices []device
}
b := run("list the block devices",
"lsblk",
"--all",
"--bytes",
"--nodeps",
"--json",
"--output", "path,ro,rm,hotplug,model,size,type,tran,vendor",
)
expect(nil, json.Unmarshal(b, &data), "list the block devices")
// Filter the block devices to get only the USB flash drives
var devices []device
for _, device := range data.Blockdevices {
if !device.RO && device.RM && device.Hotplug && device.Type == "disk" && device.Tran == "usb" {
devices = append(devices, device)
}
}
// If no USB flash drive is found, exit the program with an explanation
if len(devices) == 0 {
fmt.Println("No available USB devices were found.")
if len(data.Blockdevices) > 0 {
fmt.Println("Here is a list of the block devices found:")
table := [][]string{{"Path", "RO", "RM", "Hotplug", "Model", "Size", "Type", "Tran", "Vendor"}}
for _, device := range data.Blockdevices {
table = append(table, []string{
device.Path,
strconv.FormatBool(device.RO),
strconv.FormatBool(device.RM),
strconv.FormatBool(device.Hotplug),
device.Model.String(),
device.Size.String(),
device.Type,
device.Tran,
device.Vendor.String(),
})
}
renderTable(table)
}
return
}
// Display the found USB flash drives
table := [][]string{{"Number", "Vendor", "Model", "Size"}}
for i, device := range devices {
table = append(table, []string{
strconv.Itoa(i),
device.Vendor.String(),
device.Model.String(),
device.Size.String(),
})
}
renderTable(table)
// Select the USB flash drive to format
if len(devices) == 1 {
fmt.Println(`Press ENTER to format the disk (or "exit")`)
} else {
fmt.Println(`Enter the number of the disk you want to format (or "exit"):`)
}
var choice string
fmt.Scanln(&choice)
if strings.TrimSpace(strings.ToLower(choice)) == "exit" {
return
}
var nb int
if len(devices) > 1 {
nb, err := strconv.Atoi(choice)
if err != nil {
fatalln("Wrong disk number", choice)
}
if nb < 0 || nb >= len(devices) {
fatalln("Wrong disk number, choose between", 0, "and", len(devices)-1)
}
}
device := devices[nb]
// Get a list of the USB flash drive mount points
b, err := os.ReadFile("/proc/mounts")
expect(nil, err, "list the mount points")
lines := strings.Split(string(b), "\n")
var mountPoints []string
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
deviceName := fields[0]
mountPoint := fields[1]
if strings.Contains(deviceName, device.Path) {
mountPoints = append(mountPoints, mountPoint)
}
}
// Unmount the USB flash drive
if len(mountPoints) > 0 {
mountPointOccurrences := map[string]int{}
for _, mountPoint := range mountPoints {
mountPoint = mountPoint[1:] // remove leading '/'
parts := strings.Split(mountPoint, "/")
for i := 1; i <= len(parts); i++ {
mountPointOccurrences[strings.Join(parts[:i], "/")]++
}
}
for mountPoint, occurrences := range mountPointOccurrences {
parts := strings.Split(mountPoint, "/")
for i := len(parts) - 1; i > 0; i-- {
parent := strings.Join(parts[:i], "/")
if occurrences < mountPointOccurrences[parent] {
delete(mountPointOccurrences, mountPoint)
} else {
delete(mountPointOccurrences, parent)
}
}
}
for mountPoint := range mountPointOccurrences {
mountPoint = "/" + mountPoint // put back leading '/'
fmt.Print("The selected device is mounted on ", mountPoint, ". Trying to unmount it... ")
run("umount the selected device", "umount", "--recursive", mountPoint)
fmt.Println("done")
}
}
// Format USB flash drive
fmt.Print("Formatting... ")
run("erase disk data", "wipefs", "--all", device.Path)
run("erase disk data", "sgdisk", "--zap-all", device.Path)
run("create partition table", "sgdisk", "--largest-new", "0", device.Path)
run("create partition table", "sgdisk", "--change-name", "0:01-home", device.Path)
run("inform the OS of partition table changes", "partx", "--update", device.Path)
run("format partition", "mkfs.f2fs", "-f", device.Path+"1")
fmt.Println("done")
fmt.Println(device.Vendor, device.Model, device.Size, "has been formatted, logout and login to use it")
}
Loading…
Cancel
Save