Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 53 additions & 21 deletions core/grub.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,51 +31,83 @@ type Grub struct {
FutureRoot string
}

// generateABGrubConf generates a new grub config with the given details
func generateABGrubConf(kernelVersion string, rootPath string, rootUuid string, rootLabel string, generatedGrubConfigPath string) error {
PrintVerboseInfo("generateABGrubConf", "generating grub config for ABRoot")
// createABSpecificGrub creates a directory that contains the root specific root information
func createABSpecificGrub(kernelVersion string, rootUuid string, rootLabel string, generatedGrubConfigPath string, bootMountpoint string, filesDir string) error {
PrintVerboseInfo("createABSpecificGrub", "creating root specific grub info")

bootPrefix := filepath.Join("/abroot", rootLabel)
configDir := filepath.Join(bootMountpoint, bootPrefix)

err := MoveFile(
filepath.Join(filesDir, "vmlinuz-"+kernelVersion),
filepath.Join(configDir, "vmlinuz-"+kernelVersion),
)
if err != nil {
PrintVerboseErr("createABSpecificGrub", 1, err)
return err
}
err = MoveFile(
filepath.Join(filesDir, "initrd.img-"+kernelVersion),
filepath.Join(configDir, "initrd.img-"+kernelVersion),
)
if err != nil {
PrintVerboseErr("createABSpecificGrub", 2, err)
return err
}
err = MoveFile(
filepath.Join(filesDir, "config-"+kernelVersion),
filepath.Join(configDir, "config-"+kernelVersion),
)
if err != nil {
PrintVerboseErr("createABSpecificGrub", 3, err)
return err
}
err = MoveFile(
filepath.Join(filesDir, "System.map-"+kernelVersion),
filepath.Join(configDir, "System.map-"+kernelVersion),
)
if err != nil {
PrintVerboseErr("createABSpecificGrub", 4, err)
return err
}

kargs, err := KargsRead()
if err != nil {
PrintVerboseErr("generateABGrubConf", 0, err)
PrintVerboseErr("createABSpecificGrub", 5, err)
return err
}

var grubPath, bootPrefix, systemRoot string
var systemRoot string
if settings.Cnf.ThinProvisioning {
grubPath = filepath.Join(rootPath, "boot", "init", rootLabel)
bootPrefix = "/" + rootLabel

diskM := NewDiskManager()
sysRootPart, err := diskM.GetPartitionByLabel(rootLabel)
if err != nil {
PrintVerboseErr("generateABGrubConf", 3, err)
PrintVerboseErr("createABSpecificGrub", 6, err)
return err
}
systemRoot = "/dev/mapper/" + sysRootPart.Device
} else {
grubPath = filepath.Join(rootPath, "boot", "grub")
bootPrefix = "/.system/boot"
systemRoot = "UUID=" + rootUuid
}

confPath := filepath.Join(grubPath, "abroot.cfg")
template := ` search --no-floppy --fs-uuid --set=root %s
confPath := filepath.Join(configDir, "abroot.cfg")
template := `
linux %s/vmlinuz-%s root=%s %s
initrd %s/initrd.img-%s
`

err = os.MkdirAll(grubPath, 0755)
_ = os.RemoveAll(confPath)
err = os.MkdirAll(configDir, 0755)
if err != nil {
PrintVerboseErr("generateABGrubConf", 2, err)
PrintVerboseErr("createABSpecificGrub", 7, err)
return err
}

abrootBootConfig := fmt.Sprintf(template, rootUuid, bootPrefix, kernelVersion, systemRoot, kargs, bootPrefix, kernelVersion)
abrootBootConfig := fmt.Sprintf(template, bootPrefix, kernelVersion, systemRoot, kargs, bootPrefix, kernelVersion)

generatedGrubConfigContents, err := os.ReadFile(filepath.Join(rootPath, generatedGrubConfigPath))
generatedGrubConfigContents, err := os.ReadFile(generatedGrubConfigPath)
if err != nil {
PrintVerboseErr("generateABGrubConf", 3, "could not read grub config", err)
PrintVerboseErr("createABSpecificGrub", 8, "could not read grub config", err)
return err
}

Expand All @@ -84,18 +116,18 @@ func generateABGrubConf(kernelVersion string, rootPath string, rootUuid string,
replacementString := "REPLACED_BY_ABROOT"
if !strings.Contains(generatedGrubConfig, replacementString) {
err := errors.New("could not find replacement string \"" + replacementString + "\", check /etc/grub.d configuration")
PrintVerboseErr("generateABGrubConf", 3.1, err)
PrintVerboseErr("createABSpecificGrub", 9, err)
return err
}
grubConfigWithBootEntry := strings.Replace(generatedGrubConfig, "REPLACED_BY_ABROOT", abrootBootConfig, 1)

err = os.WriteFile(confPath, []byte(grubConfigWithBootEntry), 0644)
if err != nil {
PrintVerboseErr("generateABGrubConf", 4, "could not read grub config", err)
PrintVerboseErr("createABSpecificGrub", 10, "could not read grub config", err)
return err
}

PrintVerboseInfo("generateABGrubConf", "done")
PrintVerboseInfo("createABSpecificGrub", "done")
return nil
}

Expand Down
22 changes: 0 additions & 22 deletions core/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,25 +214,3 @@ func (a *ABRootManager) GetBoot() (partition Partition, err error) {
PrintVerboseInfo("ABRootManager.GetBoot", "successfully got boot partition")
return part, nil
}

// GetInit gets the init volume when using LVM Thin-Provisioning
func (a *ABRootManager) GetInit() (partition Partition, err error) {
PrintVerboseInfo("ABRootManager.GetInit", "running...")

// Make sure Thin-Provisioning is properly configured
if !settings.Cnf.ThinProvisioning || settings.Cnf.ThinInitVolume == "" {
return Partition{}, errors.New("ABRootManager.GetInit: error: system is not configured for thin-provisioning")
}

diskM := NewDiskManager()
part, err := diskM.GetPartitionByLabel(settings.Cnf.ThinInitVolume)
if err != nil {
err = errors.New("init volume not found")
PrintVerboseErr("ABRootManager.GetInit", 0, err)

return Partition{}, err
}

PrintVerboseInfo("ABRootManager.GetInit", "successfully got init volume")
return part, nil
}
183 changes: 64 additions & 119 deletions core/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,83 +531,30 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, freeSpace bool) err
return err
}

var rootUuid string
// If Thin-Provisioning set, mount init partition and move linux and initrd
// images to it.
var initMountpoint string
if settings.Cnf.ThinProvisioning {
initPartition, err := s.RootM.GetInit()
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.3, err)
return err
}

initMountpoint = filepath.Join(systemNew, "boot", "init")
err = initPartition.Mount(initMountpoint)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.4, err)
return err
}

cq.Add(func(args ...interface{}) error {
return initPartition.Unmount()
}, nil, 80, &goodies.NoErrorHandler{}, false)

futureInitDir := filepath.Join(initMountpoint, partFuture.Label)

err = os.RemoveAll(futureInitDir)
if err != nil {
PrintVerboseWarn("ABSystem.RunOperation", 7.44)
}
err = os.MkdirAll(futureInitDir, 0o755)
if err != nil {
PrintVerboseWarn("ABSystem.RunOperation", 7.47, err)
}

err = MoveFile(
filepath.Join(systemNew, "boot", "vmlinuz-"+newKernelVer),
filepath.Join(futureInitDir, "vmlinuz-"+newKernelVer),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.5, err)
return err
}
err = MoveFile(
filepath.Join(systemNew, "boot", "initrd.img-"+newKernelVer),
filepath.Join(futureInitDir, "initrd.img-"+newKernelVer),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.6, err)
return err
}
err = MoveFile(
filepath.Join(systemNew, "boot", "config-"+newKernelVer),
filepath.Join(futureInitDir, "config-"+newKernelVer),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.7, err)
return err
}
err = MoveFile(
filepath.Join(systemNew, "boot", "System.map-"+newKernelVer),
filepath.Join(futureInitDir, "System.map-"+newKernelVer),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.8, err)
return err
}
tmpBootMount := "/run/abroot/tmp-boot-mount-1/"
err = os.MkdirAll(tmpBootMount, 0o755)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 9, err)
return err
}

rootUuid = initPartition.Uuid
} else {
rootUuid = partFuture.Partition.Uuid
err = partBoot.Mount(tmpBootMount)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 9.1, err)
return err
}

err = generateABGrubConf(
cq.Add(func(args ...interface{}) error {
return partBoot.Unmount()
}, nil, 100, &goodies.NoErrorHandler{}, false)

err = createABSpecificGrub(
newKernelVer,
systemNew,
rootUuid,
partFuture.Partition.Uuid,
partFuture.Label,
generatedGrubConfigPath,
filepath.Join(systemNew, generatedGrubConfigPath),
tmpBootMount,
filepath.Join(systemNew, "/boot/"),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.9, err)
Expand All @@ -633,31 +580,10 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, freeSpace bool) err
return err
}

// Stage 8: Mount boot partition
// Stage 8: Apply the new rootfs
// ------------------------------------------------
PrintVerboseSimple("[Stage 8] -------- ABSystemRunOperation")

tmpBootMount := "/run/abroot/tmp-boot-mount-1/"
err = os.MkdirAll(tmpBootMount, 0o755)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 9, err)
return err
}

err = partBoot.Mount(tmpBootMount)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 9.1, err)
return err
}

cq.Add(func(args ...interface{}) error {
return partBoot.Unmount()
}, nil, 100, &goodies.NoErrorHandler{}, false)

// Stage 9: Apply the new rootfs
// ------------------------------------------------
PrintVerboseSimple("[Stage 9] -------- ABSystemRunOperation")

err = ClearDirectory(partFuture.Partition.MountPoint, []string{"new"})
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 10.1, err)
Expand Down Expand Up @@ -687,9 +613,9 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, freeSpace bool) err
return err
}

// Stage 10: Atomic swap the bootloader
// Stage 9: Atomic swap the bootloader
// ------------------------------------------------
PrintVerboseSimple("[Stage 10] -------- ABSystemRunOperation")
PrintVerboseSimple("[Stage 9] -------- ABSystemRunOperation")

grub, err := NewGrub(partBoot)
if err != nil {
Expand All @@ -707,34 +633,53 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, freeSpace bool) err
grubCfgCurrent := filepath.Join(tmpBootMount, "grub/grub.cfg")
grubCfgFuture := filepath.Join(tmpBootMount, "grub/grub.cfg.future")

// Just like in Stage 9, tmpBootMount/grub/grub.cfg.future may not exist.
if _, err = os.Stat(grubCfgFuture); os.IsNotExist(err) {
PrintVerboseInfo("ABSystem.RunOperation", "Creating grub.cfg.future")
_ = os.Remove(grubCfgFuture)

grubCfgContents, err := os.ReadFile(grubCfgCurrent)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 11.2, err)
}
const preamble string = `set timeout=5

var replacerPairs []string
if grub.FutureRoot == "a" {
replacerPairs = []string{
"default=1", "default=0",
"Previous State (A)", "Current State (A)",
"Current State (B)", "Previous State (B)",
}
} else {
replacerPairs = []string{
"default=0", "default=1",
"Current State (A)", "Previous State (A)",
"Previous State (B)", "Current State (B)",
}
}
# Load video support
insmod gfxterm
insmod all_video

# Set graphics mode
set gfxmode=1024x768,auto
terminal_output gfxterm

`

const state_a string = `
set default=0

menuentry "Current State (A)" --class abroot-a {
configfile "/abroot/%s/abroot.cfg"
}

replacer := strings.NewReplacer(replacerPairs...)
os.WriteFile(grubCfgFuture, []byte(replacer.Replace(string(grubCfgContents))), 0o644)
menuentry "Previous State (B)" --class abroot-b {
configfile "/abroot/%s/abroot.cfg"
}
`

const state_b string = `
set default=1
menuentry "Previous State (A)" --class abroot-a {
configfile "/abroot/%s/abroot.cfg"
}

menuentry "Current State (B)" --class abroot-b {
configfile "/abroot/%s/abroot.cfg"
}
`

configFile := ""

if grub.FutureRoot == "a" {
configFile = preamble + fmt.Sprintf(state_a, partFuture.Label, partPresent.Label)
} else {
configFile = preamble + fmt.Sprintf(state_b, partFuture.Label, partPresent.Label)
}

os.WriteFile(grubCfgFuture, []byte(configFile), 0o644)

err = AtomicSwap(grubCfgCurrent, grubCfgFuture)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 11.3, err)
Expand Down
4 changes: 1 addition & 3 deletions settings/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ type Config struct {
PartCryptVar string `json:"PartCryptVar"`

// Structure
ThinProvisioning bool `json:"thinProvisioning"`
ThinInitVolume string `json:"thinInitVolume"`
ThinProvisioning bool `json:"thinProvisioning"`
}

var Cnf *Config
Expand Down Expand Up @@ -150,7 +149,6 @@ func init() {

// Structure
ThinProvisioning: viper.GetBool("thinProvisioning"),
ThinInitVolume: viper.GetString("thinInitVolume"),
}
}

Expand Down