Andrew Rynhard 64c48353e2
feat: add ability to create multiple entries in extlinux.conf (#636)
Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
2019-05-10 04:50:26 -07:00

139 lines
3.1 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"
"errors"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"text/template"
)
const extlinuxConf = `DEFAULT {{ .Default }}
SAY Talos
{{- range .Labels }}
INCLUDE /{{ .Root }}/include.conf
{{ end }}`
const extlinuxConfLabel = `LABEL {{ .Root }}
KERNEL {{ .Kernel }}
INITRD {{ .Initrd }}
APPEND {{ .Append }}
`
const gptmbrbin = "/usr/lib/syslinux/gptmbr.bin"
// ExtlinuxConf reprsents the syslinux extlinux.conf file.
type ExtlinuxConf struct {
Default string
Labels []*ExtlinuxConfLabel
}
// ExtlinuxConfLabel reprsents a label in the syslinux extlinux.conf file.
type ExtlinuxConfLabel 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 invoking 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, 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 extlinux with the
// specified kernel parameters.
func Install(base string, config interface{}) (err error) {
extlinuxconf, ok := config.(*ExtlinuxConf)
if !ok {
return errors.New("expected extlinux")
}
path := filepath.Join(base, "extlinux", "extlinux.conf")
if err = WriteExtlinuxConf(base, path, extlinuxconf); err != nil {
return err
}
if err = cmd("extlinux", "--install", filepath.Dir(path)); err != nil {
return err
}
return nil
}
// WriteExtlinuxConf write extlinux.conf to disk.
func WriteExtlinuxConf(base, path string, extlinuxconf *ExtlinuxConf) (err error) {
b := []byte{}
wr := bytes.NewBuffer(b)
t := template.Must(template.New("extlinux").Parse(extlinuxConf))
if err = t.Execute(wr, extlinuxconf); err != nil {
return err
}
dir := filepath.Dir(path)
if err = os.MkdirAll(dir, os.ModeDir); err != nil {
return err
}
log.Println("writing extlinux.conf to disk")
if err = ioutil.WriteFile(path, wr.Bytes(), 0600); err != nil {
return err
}
for _, label := range extlinuxconf.Labels {
b = []byte{}
wr = bytes.NewBuffer(b)
t = template.Must(template.New("extlinux").Parse(extlinuxConfLabel))
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 extlinux label %s to disk", label.Root)
if err = ioutil.WriteFile(filepath.Join(dir, "include.conf"), wr.Bytes(), 0600); err != nil {
return err
}
}
return nil
}
func cmd(name string, args ...string) error {
cmd := exec.Command(name, args...)
err := cmd.Start()
if err != nil {
return err
}
return cmd.Wait()
}