85 lines
2.5 KiB
Go
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()
|
|
}
|