102 lines
2 KiB
Go
102 lines
2 KiB
Go
package prober
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.faercol.me/faercol/http-boot-config/config/logger"
|
|
)
|
|
|
|
var efiBootmgrRegexp = regexp.MustCompile(`Boot(?P<id>\d+)\* (?P<name>[\w ]+)\t(\w+\(.*\))/File\((?P<filepath>.+)\)`)
|
|
var activeRegexp = regexp.MustCompile(`BootCurrent: (\d+)`)
|
|
|
|
type EfiApp struct {
|
|
ID int
|
|
Name string
|
|
Path string
|
|
Active bool
|
|
}
|
|
|
|
func efiAppFromBootMgrOutput(rawVal string, activeId int) (app EfiApp, ok bool) {
|
|
match := efiBootmgrRegexp.FindStringSubmatch(rawVal)
|
|
if len(match) == 0 {
|
|
return
|
|
}
|
|
result := make(map[string]string)
|
|
for i, name := range efiBootmgrRegexp.SubexpNames() {
|
|
if i != 0 && name != "" {
|
|
result[name] = match[i]
|
|
}
|
|
}
|
|
id, ok := result["id"]
|
|
if !ok {
|
|
return
|
|
}
|
|
idInt, err := strconv.Atoi(id)
|
|
if err != nil {
|
|
return app, false
|
|
}
|
|
name, ok := result["name"]
|
|
if !ok {
|
|
return
|
|
}
|
|
filepath, ok := result["filepath"]
|
|
if !ok {
|
|
return
|
|
}
|
|
return EfiApp{
|
|
ID: idInt,
|
|
Name: strings.TrimSpace(name),
|
|
Path: strings.TrimSpace(filepath),
|
|
Active: idInt == activeId,
|
|
}, true
|
|
}
|
|
|
|
func getActiveEFIApp(output string) (int, error) {
|
|
match := activeRegexp.FindStringSubmatch(output)
|
|
if len(match) == 0 {
|
|
return -1, errors.New("no active boot image found")
|
|
}
|
|
strId := match[1]
|
|
id, err := strconv.Atoi(strId)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func GetEFIApps(log *logger.SimpleLogger) (apps []EfiApp, err error) {
|
|
cmd := exec.Command("/usr/bin/efibootmgr")
|
|
var out bytes.Buffer
|
|
cmd.Stdout = &out
|
|
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if cmd.ProcessState.ExitCode() != 0 {
|
|
return nil, fmt.Errorf("error running efibootmgr, returncode %d", cmd.ProcessState.ExitCode())
|
|
}
|
|
|
|
outStr := out.String()
|
|
activeBootID, err := getActiveEFIApp(outStr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, l := range strings.Split(outStr, "\n") {
|
|
log.Debugf("Parsing line %q", l)
|
|
app, ok := efiAppFromBootMgrOutput(l, activeBootID)
|
|
if !ok {
|
|
log.Debug("Line is not a valid EFI application")
|
|
continue
|
|
}
|
|
apps = append(apps, app)
|
|
}
|
|
return
|
|
}
|