mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-21 22:51:13 +02:00
This moves to using BLKPG ioctl instead of BLKRRPART. BLKRRPART is older and more sensitive to EBUSY errors. BLKPG has the potential to minimize the changes of encountering an EBUSY error when manipulating partition tables. In looking at a comparison between BLKPG and BLKRRPART, it seems that both have their pros and cons. Eventually a combination of the two may serve us better, but for now I think BLKPG will get us further. Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
163 lines
3.6 KiB
Go
163 lines
3.6 KiB
Go
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
package syslinux
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"text/template"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/talos-systems/talos/pkg/cmd"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const syslinuxCfgTpl = `DEFAULT {{ .Default }}
|
|
SAY Talos
|
|
{{- range .Labels }}
|
|
INCLUDE /{{ .Root }}/include.cfg
|
|
{{- end }}`
|
|
|
|
const syslinuxLabelTpl = `LABEL {{ .Root }}
|
|
KERNEL {{ .Kernel }}
|
|
INITRD {{ .Initrd }}
|
|
APPEND {{ .Append }}
|
|
`
|
|
|
|
const (
|
|
gptmbrbin = "/usr/lib/syslinux/gptmbr.bin"
|
|
syslinuxefi = "/usr/lib/syslinux/syslinux.efi"
|
|
ldlinuxe64 = "/usr/lib/syslinux/ldlinux.e64"
|
|
)
|
|
|
|
// Cfg reprsents the syslinux.cfg file.
|
|
type Cfg struct {
|
|
Default string
|
|
Labels []*Label
|
|
}
|
|
|
|
// Label reprsents a label in the syslinux.cfg file.
|
|
type Label struct {
|
|
Root string
|
|
Kernel string
|
|
Initrd string
|
|
Append string
|
|
}
|
|
|
|
// Syslinux represents the syslinux bootloader.
|
|
type Syslinux struct{}
|
|
|
|
// Prepare implements the Bootloader interface. It works by writing
|
|
// gptmbr.bin to a block device.
|
|
func Prepare(dev string) (err error) {
|
|
b, err := ioutil.ReadFile(gptmbrbin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(dev, os.O_WRONLY|unix.O_CLOEXEC, os.ModeDevice)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// nolint: errcheck
|
|
defer f.Close()
|
|
if _, err := f.Write(b); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Install implements the Bootloader interface. It sets up syslinux with the
|
|
// specified kernel parameters.
|
|
func Install(base string, config interface{}) (err error) {
|
|
syslinuxcfg, ok := config.(*Cfg)
|
|
if !ok {
|
|
return errors.New("expected a syslinux config")
|
|
}
|
|
|
|
efiDir := filepath.Join(base, "EFI", "BOOT")
|
|
if err = os.MkdirAll(efiDir, 0700); err != nil {
|
|
return err
|
|
}
|
|
|
|
input, err := ioutil.ReadFile(syslinuxefi)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = ioutil.WriteFile(efiDir+"/BOOTX64.EFI", input, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
input, err = ioutil.ReadFile(ldlinuxe64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = ioutil.WriteFile(efiDir+"/ldlinux.e64", input, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
paths := []string{filepath.Join(base, "syslinux", "syslinux.cfg"), filepath.Join(base, "EFI", "syslinux", "syslinux.cfg")}
|
|
for _, path := range paths {
|
|
if err = WriteSyslinuxCfg(base, path, syslinuxcfg); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err = cmd.Run("extlinux", "--install", filepath.Dir(paths[0])); err != nil {
|
|
return errors.Wrap(err, "failed to install extlinux")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// WriteSyslinuxCfg write syslinux.cfg to disk.
|
|
func WriteSyslinuxCfg(base, path string, syslinuxcfg *Cfg) (err error) {
|
|
b := []byte{}
|
|
wr := bytes.NewBuffer(b)
|
|
t := template.Must(template.New("syslinux").Parse(syslinuxCfgTpl))
|
|
if err = t.Execute(wr, syslinuxcfg); err != nil {
|
|
return err
|
|
}
|
|
|
|
dir := filepath.Dir(path)
|
|
if err = os.MkdirAll(dir, os.ModeDir); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("writing %s to disk", path)
|
|
if err = ioutil.WriteFile(path, wr.Bytes(), 0600); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, label := range syslinuxcfg.Labels {
|
|
b = []byte{}
|
|
wr = bytes.NewBuffer(b)
|
|
t = template.Must(template.New("syslinux").Parse(syslinuxLabelTpl))
|
|
if err = t.Execute(wr, label); err != nil {
|
|
return err
|
|
}
|
|
|
|
dir = filepath.Join(base, label.Root)
|
|
if err = os.MkdirAll(dir, os.ModeDir); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("writing syslinux label %s to disk", label.Root)
|
|
if err = ioutil.WriteFile(filepath.Join(dir, "include.cfg"), wr.Bytes(), 0600); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|