diff --git a/core/grub.go b/core/grub.go index 63037318..950fa899 100644 --- a/core/grub.go +++ b/core/grub.go @@ -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 } @@ -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 } diff --git a/core/root.go b/core/root.go index 6ca0153b..f5acaf11 100644 --- a/core/root.go +++ b/core/root.go @@ -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 -} diff --git a/core/system.go b/core/system.go index 8d777950..e7cd97c1 100644 --- a/core/system.go +++ b/core/system.go @@ -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) @@ -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) @@ -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 { @@ -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) diff --git a/settings/config.go b/settings/config.go index 8cc21081..991e73d7 100644 --- a/settings/config.go +++ b/settings/config.go @@ -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 @@ -150,7 +149,6 @@ func init() { // Structure ThinProvisioning: viper.GetBool("thinProvisioning"), - ThinInitVolume: viper.GetString("thinInitVolume"), } }