local-server/cmd/dkl-local-server/boot-img.go
2018-11-15 18:07:10 +11:00

164 lines
2.8 KiB
Go

package main
import (
"archive/tar"
"compress/gzip"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"github.com/pierrec/lz4"
)
func buildBootImg(out io.Writer, ctx *renderContext) (err error) {
bootImg, err := ioutil.TempFile(os.TempDir(), "boot.img-")
if err != nil {
return
}
defer rmTempFile(bootImg)
// 2MB + 2GB + 2MB + 34 sectors
bootImg.Truncate(2<<30 + 4<<20 + 34*512)
// partition
err = run("sgdisk",
"--new=0:4096:+2G", "--typecode=0:EF00", "-c", "0:boot",
"--new=0:0:+2M", "--typecode=0:EF02", "-c", "0:BIOS-BOOT",
"--hybrid=1:2", "--print", bootImg.Name())
if err != nil {
return
}
err = setupBootImage(bootImg, ctx)
if err != nil {
return
}
// send the result
bootImg.Seek(0, os.SEEK_SET)
io.Copy(out, bootImg)
return
}
func buildBootImgLZ4(out io.Writer, ctx *renderContext) (err error) {
lz4Out := lz4.NewWriter(out)
if err = buildBootImg(lz4Out, ctx); err != nil {
return
}
lz4Out.Close()
return
}
func buildBootImgGZ(out io.Writer, ctx *renderContext) (err error) {
gzOut := gzip.NewWriter(out)
if err = buildBootImg(gzOut, ctx); err != nil {
return
}
gzOut.Close()
return
}
func setupBootImage(bootImg *os.File, ctx *renderContext) (err error) {
devb, err := exec.Command("losetup", "--find", "--show", "--partscan", bootImg.Name()).CombinedOutput()
if err != nil {
return
}
dev := strings.TrimSpace(string(devb))
defer run("losetup", "-d", dev)
log.Print("device: ", dev)
err = run("mkfs.vfat", "-n", "DKLBOOT", dev+"p1")
if err != nil {
return
}
tempDir := bootImg.Name() + ".p1.mount"
err = os.Mkdir(tempDir, 0755)
if err != nil {
return
}
defer func() {
log.Print("Removing ", tempDir)
os.RemoveAll(tempDir)
}()
err = syscall.Mount(dev+"p1", tempDir, "vfat", 0, "")
if err != nil {
return
}
defer func() {
log.Print("Unmounting ", tempDir)
syscall.Unmount(tempDir, 0)
}()
// setup grub
err = run("/scripts/grub_install.sh", bootImg.Name(), dev, tempDir)
if err != nil {
return
}
// add system elements
tarOut, tarIn := io.Pipe()
go func() {
err2 := buildBootTar(tarIn, ctx)
tarIn.Close()
if err2 != nil {
err = err2
}
}()
defer tarOut.Close()
tarRd := tar.NewReader(tarOut)
for {
hdr, err := tarRd.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
log.Print("tar: extracting ", hdr.Name)
outPath := filepath.Join(tempDir, hdr.Name)
os.MkdirAll(filepath.Dir(outPath), 0755)
f, err := os.Create(outPath)
if err != nil {
return err
}
_, err = io.Copy(f, tarRd)
f.Close()
if err != nil {
return err
}
}
return
}
func run(program string, args ...string) (err error) {
cmd := exec.Command(program, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}