Skip to content

Commit

Permalink
Merge branch 'morten/fix-esp'
Browse files Browse the repository at this point in the history
* morten/fix-esp:
  fix esp detection with multiple mountpoints and failing udev info
  • Loading branch information
Foxboron committed Aug 16, 2024
2 parents 32f8838 + 436750b commit a53a6ba
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 52 deletions.
118 changes: 66 additions & 52 deletions sbctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path/filepath"
"slices"

"github.com/foxboron/sbctl/backend"
"github.com/foxboron/sbctl/config"
Expand All @@ -25,26 +26,82 @@ var (
// Functions that doesn't fit anywhere else

type LsblkEntry struct {
Parttype string `json:"parttype"`
Mountpoint string `json:"mountpoint"`
Pttype string `json:"pttype"`
Fstype string `json:"fstype"`
Parttype string `json:"parttype"`
Mountpoint string `json:"mountpoint"`
Mountpoints []string `json:"mountpoints"`
Pttype string `json:"pttype"`
Fstype string `json:"fstype"`
Children []*LsblkEntry `json:"children"`
}

type LsblkRoot struct {
Blockdevices []LsblkEntry `json:"blockdevices"`
Blockdevices []*LsblkEntry `json:"blockdevices"`
}

var espLocations = []string{
"/efi",
"/boot",
"/boot/efi",
"/efi",
}
var ErrNoESP = errors.New("failed to find EFI system partition")

func findESP(b []byte) (string, error) {
var lsblkRoot LsblkRoot

if err := json.Unmarshal(b, &lsblkRoot); err != nil {
return "", fmt.Errorf("failed to parse json: %v", err)
}

for _, lsblkEntry := range lsblkRoot.Blockdevices {
// This is our check function, that also checks mountpoints
checkDev := func(e *LsblkEntry, pttype string) *LsblkEntry {
if e.Pttype != "gpt" && (e.Pttype != "" && pttype != "gpt") {
return nil
}

if e.Fstype != "vfat" {
return nil
}

if e.Parttype != "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" {
return nil
}

if slices.Contains(espLocations, e.Mountpoint) {
return e
}

for _, esp := range espLocations {
n := slices.Index(e.Mountpoints, esp)
if n == -1 {
continue
}
// Replace the top-level Mountpoint with a valid one from mountpoints
e.Mountpoint = e.Mountpoints[n]
return e
}
return nil
}

// First check top-level devices
p := checkDev(lsblkEntry, "")
if p != nil {
return p.Mountpoint, nil
}

// Check children, this is not recursive.
for _, ce := range lsblkEntry.Children {
p := checkDev(ce, lsblkEntry.Pttype)
if p != nil {
return p.Mountpoint, nil
}
}
}
return "", ErrNoESP
}

// Slightly more advanced check
func GetESP(vfs afero.Fs) (string, error) {

for _, env := range []string{"SYSTEMD_ESP_PATH", "ESP_PATH"} {
envEspPath, found := os.LookupEnv(env)
if found {
Expand All @@ -61,55 +118,12 @@ func GetESP(vfs afero.Fs) (string, error) {
out, err := exec.Command(
"lsblk",
"--json",
"--tree",
"--output", "PARTTYPE,MOUNTPOINT,PTTYPE,FSTYPE").Output()
if err != nil {
return "", err
}

var lsblkRoot LsblkRoot
if err = json.Unmarshal(out, &lsblkRoot); err != nil {
return "", fmt.Errorf("failed to parse json: %v", err)
}

var pathBootEntry *LsblkEntry
var pathBootEfiEntry *LsblkEntry
var pathEfiEntry *LsblkEntry

for _, lsblkEntry := range lsblkRoot.Blockdevices {
switch lsblkEntry.Mountpoint {
case "/boot":
pathBootEntry = new(LsblkEntry)
*pathBootEntry = lsblkEntry
case "/boot/efi":
pathBootEfiEntry = new(LsblkEntry)
*pathBootEfiEntry = lsblkEntry
case "/efi":
pathEfiEntry = new(LsblkEntry)
*pathEfiEntry = lsblkEntry
}
}

for _, entryToCheck := range []*LsblkEntry{pathEfiEntry, pathBootEntry, pathBootEfiEntry} {
if entryToCheck == nil {
continue
}

if entryToCheck.Pttype != "gpt" {
continue
}

if entryToCheck.Fstype != "vfat" {
continue
}

if entryToCheck.Parttype != "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" {
continue
}

return entryToCheck.Mountpoint, nil
}

return "", ErrNoESP
return findESP(out)
}

func Sign(state *config.State, keys *backend.KeyHierarchy, file, output string, enroll bool) error {
Expand Down
32 changes: 32 additions & 0 deletions sbctl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package sbctl

import (
"testing"
)

func TestGetESP(t *testing.T) {
for _, c := range []struct {
lsblk []byte
esp string
wantErr error
}{
{
lsblk: []byte(`{"blockdevices":[{"parttype":null,"mountpoint":null,"pttype":"gpt","fstype":"crypto_LUKS","mountpoints":[null],"children":[{"parttype":"c12a7328-f81f-11d2-ba4b-00a0c93ec93b","mountpoint":"/efi","pttype":"gpt","fstype":"vfat","mountpoints":["/efi"]},{"parttype":"4f68bce3-e8cd-4db1-96e7-fbcaf984b709","mountpoint":null,"pttype":"gpt","fstype":"crypto_LUKS","mountpoints":[null],"children":[{"parttype":null,"mountpoint":"/home/.snapshots","pttype":null,"fstype":"btrfs","mountpoints":["/home/.snapshots","/home","/var","/srv","/"]}]}]}]}`),
esp: "/efi",
wantErr: nil,
},
{
lsblk: []byte(`{"blockdevices":[{"parttype":null,"mountpoint":null,"pttype":"gpt","fstype":"crypto_LUKS","mountpoints":[null],"children":[{"parttype":"c12a7328-f81f-11d2-ba4b-00a0c93ec93b","mountpoint":"/efi","pttype":null,"fstype":"vfat","mountpoints":["/efi"]},{"parttype":"4f68bce3-e8cd-4db1-96e7-fbcaf984b709","mountpoint":null,"pttype":null,"fstype":"crypto_LUKS","mountpoints":[null],"children":[{"parttype":null,"mountpoint":"/home/.snapshots","pttype":null,"fstype":"btrfs","mountpoints":["/home/.snapshots","/home","/var","/srv","/"]}]}]}]}`),
esp: "/efi",
wantErr: nil,
},
} {
esp, err := findESP(c.lsblk)
if err != nil {
t.Fatalf("%v", err)
}
if esp != c.esp {
t.Fatalf("wrong esp")
}
}
}

0 comments on commit a53a6ba

Please sign in to comment.