gloader/main.go

179 lines
4.1 KiB
Go

package main
import (
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/u-root/u-root/pkg/mount/gpt"
)
var (
perm = flag.String("perm", "/perm", "new val for perm")
gloaderHome = "/perm/gloader"
)
func main() {
flag.Parse()
gloaderHome = filepath.Join(*perm, "gloader")
os.MkdirAll(gloaderHome, 0777)
err := mount()
if err != nil {
log.Println(err)
os.Exit(1)
}
d := newDownloader()
d.DataDir = filepath.Join(gloaderHome, "data")
d.Start("tcp", ":8844")
}
func mount() error {
var (
partUUIDb []byte
partUUID string
dev part
err error
dataStat os.FileInfo
dataDir = filepath.Join(gloaderHome, "data")
)
partUUIDb, err = ioutil.ReadFile(filepath.Join(gloaderHome, "partition"))
partUUID = strings.TrimSpace(string(partUUIDb))
if err != nil || partUUID == "" {
return nil
}
dataStat, err = os.Stat(dataDir)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
err = os.MkdirAll(dataDir, 0o755)
if err != nil {
return fmt.Errorf("error creating datadir: %w", err)
}
dataStat, err = os.Stat(dataDir)
if err != nil {
return fmt.Errorf("error mounting datadir: %w", err)
}
} else {
return fmt.Errorf("error mounting datadir: %w", err)
}
}
if dataStat.IsDir() {
var folder *os.File
folder, err = os.Open(dataDir)
if err != nil {
return fmt.Errorf("error mounting datadir: %w", err)
}
_, err = folder.Readdir(1)
if errors.Is(err, io.EOF) {
fmt.Printf("mount %s %s", partUUID, dataDir)
dev = findPartUUID(partUUID)
if err != nil {
return fmt.Errorf("error mounting datadir: %w", err)
}
err = syscall.Mount(dev.Path, dataDir, "ext4", 0, "")
if err != nil {
return fmt.Errorf("error mounting datadir: %w", err)
}
return nil
}
return fmt.Errorf("error mounting datadir: %w", err)
}
return fmt.Errorf("error mounting datadir: data dir %s is not a directory", dataDir)
}
// func findPartUUID(uuid string) (string, error) {
// var dev string
// err := filepath.Walk("/sys/block", func(path string, info os.FileInfo, err error) error {
// if err != nil {
// log.Printf("findPartUUID: %v", err)
// return nil
// }
// if info.Mode()&os.ModeSymlink == 0 {
// return nil
// }
// devname := "/dev/" + filepath.Base(path)
// f, err := os.Open(devname)
// if err != nil {
// log.Printf("findPartUUID: %v", err)
// return nil
// }
// defer f.Close()
// if _, err := f.Seek(440, io.SeekStart); err != nil {
// var se syscall.Errno
// if errors.As(err, &se) && se == syscall.EINVAL {
// // Seek()ing empty loop devices results in EINVAL.
// return nil
// }
// log.Printf("findPartUUID: %v(%T)", err, err.(*os.PathError).Err)
// return nil
// }
// var diskSig struct {
// ID uint32
// Trailer uint16
// }
// if err := binary.Read(f, binary.LittleEndian, &diskSig); err != nil {
// log.Printf("findPartUUID: %v", err)
// return nil
// }
// if fmt.Sprintf("%08x", diskSig.ID) == uuid && diskSig.Trailer == 0 {
// dev = devname
// // TODO: abort early with sentinel error code
// return nil
// }
// return nil
// })
// if err != nil {
// return "", err
// }
// if dev == "" {
// return "", fmt.Errorf("PARTUUID=%s not found", uuid)
// }
// return dev, nil
// }
type part struct {
UUID string
Path string
}
func findPartUUID(UUID string) part {
var dev part
err := filepath.Walk("/sys/block", func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Printf("listPartUUID: %v", err)
return nil
}
if info.Mode()&os.ModeSymlink == 0 {
return nil
}
devname := "/dev/" + filepath.Base(path)
f, err := os.Open(devname)
if err != nil {
log.Printf("listPartUUID: %v", err)
return nil
}
defer f.Close()
parttable, _ := gpt.New(f)
if parttable.Primary != nil {
for i, partition := range parttable.Primary.Parts {
if partition.UniqueGUID.String() == UUID {
dev = part{UUID: partition.UniqueGUID.String(), Path: devname + strconv.Itoa(i+1)}
}
}
}
return nil
})
if err != nil {
return part{}
}
return dev
}