2020-05-03 12:41:09 -05:00
|
|
|
package sbctl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2021-05-13 05:33:58 -05:00
|
|
|
"errors"
|
2020-05-03 12:41:09 -05:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Bundle struct {
|
|
|
|
Output string `json:"output"`
|
|
|
|
IntelMicrocode string `json:"intel_microcode"`
|
|
|
|
AMDMicrocode string `json:"amd_microcode"`
|
|
|
|
KernelImage string `json:"kernel_image"`
|
|
|
|
Initramfs string `json:"initramfs"`
|
|
|
|
Cmdline string `json:"cmdline"`
|
|
|
|
Splash string `json:"splash"`
|
|
|
|
OSRelease string `json:"os_release"`
|
|
|
|
EFIStub string `json:"efi_stub"`
|
|
|
|
ESP string `json:"esp"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Bundles map[string]*Bundle
|
|
|
|
|
|
|
|
var BundleDBPath = filepath.Join(DatabasePath, "bundles.db")
|
|
|
|
|
2021-01-10 21:47:03 -06:00
|
|
|
func ReadBundleDatabase(dbpath string) (Bundles, error) {
|
|
|
|
f, err := ReadOrCreateFile(dbpath)
|
2020-05-03 12:41:09 -05:00
|
|
|
if err != nil {
|
2021-01-10 21:47:03 -06:00
|
|
|
return nil, err
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
2021-01-10 21:47:03 -06:00
|
|
|
bundles := make(Bundles)
|
2020-05-03 12:41:09 -05:00
|
|
|
json.Unmarshal(f, &bundles)
|
2021-01-10 21:47:03 -06:00
|
|
|
return bundles, nil
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
|
|
|
|
2021-05-19 18:08:45 -05:00
|
|
|
func WriteBundleDatabase(dbpath string, bundles Bundles) error {
|
2020-05-03 12:41:09 -05:00
|
|
|
data, err := json.MarshalIndent(bundles, "", " ")
|
|
|
|
if err != nil {
|
2021-05-19 18:08:45 -05:00
|
|
|
return err
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
2021-05-16 13:14:42 -05:00
|
|
|
err = os.WriteFile(dbpath, data, 0644)
|
2020-05-03 12:41:09 -05:00
|
|
|
if err != nil {
|
2021-05-19 18:08:45 -05:00
|
|
|
return err
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
2021-05-19 18:08:45 -05:00
|
|
|
return nil
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
|
|
|
|
2021-05-18 12:57:40 -05:00
|
|
|
func BundleIter(fn func(s *Bundle) error) error {
|
|
|
|
files, err := ReadBundleDatabase(BundleDBPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, s := range files {
|
|
|
|
if err := fn(s); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-08 12:08:43 -05:00
|
|
|
func GetEfistub() string {
|
|
|
|
candidates := []string{
|
|
|
|
"/lib/systemd/boot/efi/linuxx64.efi.stub",
|
|
|
|
"/lib/gummiboot/linuxx64.efi.stub",
|
|
|
|
}
|
|
|
|
for _, f := range candidates {
|
|
|
|
if _, err := os.Stat(f); err == nil {
|
|
|
|
return f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2021-06-28 01:02:33 -05:00
|
|
|
func NewBundle() (bundle *Bundle, err error) {
|
|
|
|
esp, err := GetESP()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2020-06-08 12:08:43 -05:00
|
|
|
|
|
|
|
stub := GetEfistub()
|
|
|
|
if stub == "" {
|
|
|
|
panic("No EFISTUB file found. Please install systemd-boot or gummiboot!")
|
|
|
|
}
|
|
|
|
|
2021-06-28 01:02:33 -05:00
|
|
|
bundle = &Bundle{
|
2020-05-03 12:41:09 -05:00
|
|
|
Output: "",
|
|
|
|
IntelMicrocode: "",
|
|
|
|
AMDMicrocode: "",
|
2021-05-30 07:15:02 -05:00
|
|
|
KernelImage: "/boot/vmlinuz-linux",
|
|
|
|
Initramfs: "/boot/initramfs-linux.img",
|
2021-04-05 09:23:14 -05:00
|
|
|
Cmdline: "/etc/kernel/cmdline",
|
2020-05-03 12:41:09 -05:00
|
|
|
Splash: "",
|
|
|
|
OSRelease: "/usr/lib/os-release",
|
2020-06-08 12:08:43 -05:00
|
|
|
EFIStub: stub,
|
2020-05-03 12:41:09 -05:00
|
|
|
ESP: esp,
|
|
|
|
}
|
2021-06-28 01:02:33 -05:00
|
|
|
|
|
|
|
return
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
|
|
|
|
2021-05-16 18:47:33 -05:00
|
|
|
func GenerateBundle(bundle *Bundle) (bool, error) {
|
2021-05-04 14:25:54 -05:00
|
|
|
args := []string{
|
|
|
|
"--add-section", fmt.Sprintf(".osrel=%s", bundle.OSRelease), "--change-section-vma", ".osrel=0x20000",
|
|
|
|
"--add-section", fmt.Sprintf(".cmdline=%s", bundle.Cmdline), "--change-section-vma", ".cmdline=0x30000",
|
|
|
|
"--add-section", fmt.Sprintf(".linux=%s", bundle.KernelImage), "--change-section-vma", ".linux=0x2000000",
|
|
|
|
"--add-section", fmt.Sprintf(".initrd=%s", bundle.Initramfs), "--change-section-vma", ".initrd=0x3000000",
|
|
|
|
}
|
|
|
|
|
2020-05-03 12:41:09 -05:00
|
|
|
if bundle.Splash != "" {
|
2021-05-04 14:25:54 -05:00
|
|
|
args = append(args, "--add-section", fmt.Sprintf(".splash=%s", bundle.Splash), "--change-section-vma", ".splash=0x40000")
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
2021-05-04 14:25:54 -05:00
|
|
|
|
|
|
|
args = append(args, bundle.EFIStub, bundle.Output)
|
|
|
|
cmd := exec.Command("objcopy", args...)
|
2020-05-03 12:41:09 -05:00
|
|
|
cmd.Stdout = os.Stdout
|
2021-05-05 03:15:50 -05:00
|
|
|
cmd.Stderr = os.Stderr
|
2020-05-03 12:41:09 -05:00
|
|
|
if err := cmd.Run(); err != nil {
|
2021-05-13 05:33:58 -05:00
|
|
|
if errors.Is(err, exec.ErrNotFound) {
|
2021-05-16 18:47:33 -05:00
|
|
|
return false, err
|
2021-05-13 05:33:58 -05:00
|
|
|
}
|
2020-05-03 12:41:09 -05:00
|
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
2021-05-16 18:47:33 -05:00
|
|
|
return exitError.ExitCode() == 0, nil
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|
|
|
|
}
|
2021-05-16 18:47:33 -05:00
|
|
|
return true, nil
|
2020-05-03 12:41:09 -05:00
|
|
|
}
|