clonetool/boot_linux.go
2026-09-06 20:15:54 +02:00

85 lines
2.5 KiB
Go

//go:build linux
package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
)
// reinstallBootloader mounts the freshly cloned root (and ESP), bind-mounts
// the API filesystems, and runs grub-install + grub-mkconfig inside a chroot.
// It is best-effort: it returns a human summary and never a hard error, so a
// clone still completes even when boot repair cannot.
func reinstallBootloader(diskPath, optsJSON string) string {
var o bootOpts
if err := json.Unmarshal([]byte(optsJSON), &o); err != nil {
return "skipped: bad boot opts: " + err.Error()
}
if o.RootPart == 0 {
return "skipped: no root partition identified (pass --reinstall-bootloader only for a Linux system disk)"
}
att, err := attachDisk(diskPath, true)
if err != nil {
return "skipped: attach: " + err.Error()
}
defer att.cleanup()
rootNode := partNode(att.blockPath, o.RootPart)
root, umount, err := mountAt(rootNode, false)
if err != nil {
return "skipped: mount root: " + err.Error()
}
defer umount()
if o.ESPPart != 0 {
espNode := partNode(att.blockPath, o.ESPPart)
espDir := root + "/boot/efi"
_ = os.MkdirAll(espDir, 0755)
if out, err := exec.Command("mount", espNode, espDir).CombinedOutput(); err != nil {
return "skipped: mount ESP: " + strings.TrimSpace(string(out))
}
defer exec.Command("umount", espDir).Run()
}
var log strings.Builder
for _, d := range []string{"dev", "proc", "sys", "run"} {
_ = exec.Command("mount", "--bind", "/"+d, root+"/"+d).Run()
defer exec.Command("umount", "-l", root+"/"+d).Run()
}
grubTarget := att.blockPath
if isDevicePath(diskPath) || looksLikeBlockDevice(diskPath) {
grubTarget = diskPath
}
giArgs := []string{root, "grub-install", "--recheck"}
if o.UEFI {
giArgs = append(giArgs, "--target=x86_64-efi", "--efi-directory=/boot/efi", "--removable")
} else {
giArgs = append(giArgs, grubTarget)
}
if out, err := exec.Command("chroot", giArgs...).CombinedOutput(); err != nil {
fmt.Fprintf(&log, "grub-install failed: %s; ", strings.TrimSpace(string(out)))
} else {
log.WriteString("grub-install ok; ")
}
mkcfg := "grub-mkconfig"
if _, err := exec.LookPath("update-grub"); err == nil {
mkcfg = "update-grub"
}
args := []string{root, mkcfg}
if mkcfg == "grub-mkconfig" {
args = append(args, "-o", "/boot/grub/grub.cfg")
}
if out, err := exec.Command("chroot", args...).CombinedOutput(); err != nil {
fmt.Fprintf(&log, "%s failed: %s", mkcfg, strings.TrimSpace(string(out)))
} else {
log.WriteString(mkcfg + " ok")
}
return log.String()
}