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() }