...

Source file src/edge-infra.dev/pkg/sds/lib/os/grub/grub.go

Documentation: edge-infra.dev/pkg/sds/lib/os/grub

     1  package grub
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"path/filepath"
     7  	"regexp"
     8  	"strings"
     9  
    10  	file "edge-infra.dev/pkg/sds/lib/os/file"
    11  )
    12  
    13  type CfgFile interface {
    14  	WriteGrubCfg(fileHandler file.File, cfgPath string) error
    15  	SetProperty(property, value string)
    16  	GetMenuEntries() []MenuEntry
    17  	GetMenuEntry(name string) (*MenuEntry, error)
    18  	AddMenuEntry(menuEntry MenuEntry)
    19  	DeleteMenuEntry(entryName string)
    20  	WriteGrubCfgReadWrite(fileHandler file.File, grubVolumeMountPath, cfgPath string) error
    21  	UpdateRequired() bool
    22  }
    23  
    24  type grubFile struct {
    25  	Contents         string
    26  	OriginalContents string
    27  }
    28  
    29  type MenuEntry struct {
    30  	Name     string
    31  	Options  string
    32  	Contents []string
    33  }
    34  
    35  func GetGrubConfigPath(fileHandler file.File, grubVolumeMountPath string, grubConfigFileName string) (string, error) {
    36  	efi := filepath.Join(grubVolumeMountPath, "efi", "EFI", "grub", grubConfigFileName)
    37  	legacy := filepath.Join(grubVolumeMountPath, "grub", grubConfigFileName)
    38  
    39  	if fileHandler.Exists(efi) {
    40  		return efi, nil
    41  	} else if fileHandler.Exists(legacy) {
    42  		return legacy, nil
    43  	}
    44  	return "", fmt.Errorf("grub config path not found. Efi: %s Legacy: %s", efi, legacy)
    45  }
    46  
    47  func ReadGrubCfg(fileHandler file.File, cfgPath string) (CfgFile, error) {
    48  	grubContentBytes, err := fileHandler.Read(cfgPath)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	grubContent := &grubFile{
    53  		Contents:         string(grubContentBytes),
    54  		OriginalContents: string(grubContentBytes),
    55  	}
    56  
    57  	return grubContent, nil
    58  }
    59  
    60  func (grubFile *grubFile) UpdateRequired() bool {
    61  	return grubFile.OriginalContents != grubFile.Contents
    62  }
    63  
    64  func (grubFile *grubFile) WriteGrubCfg(fileHandler file.File, cfgPath string) error {
    65  	err := fileHandler.Write(cfgPath+".swp", []byte(grubFile.Contents), 0400)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	return fileHandler.Rename(cfgPath+".swp", cfgPath)
    70  }
    71  
    72  func (grubFile *grubFile) WriteGrubCfgReadWrite(fileHandler file.File, grubVolumeMountPath, cfgPath string) error {
    73  	return fileHandler.WriteWithFsReadWrite(grubVolumeMountPath, cfgPath, []byte(grubFile.Contents), 0400)
    74  }
    75  
    76  func (grubFile *grubFile) SetProperty(property, value string) {
    77  	setStr := "set " + property
    78  	newLine := fmt.Sprintf("%s=%s", setStr, value)
    79  	if strings.Contains(grubFile.Contents, setStr) {
    80  		re := regexp.MustCompile(setStr + "=.*")
    81  		grubFile.Contents = re.ReplaceAllLiteralString(grubFile.Contents, newLine)
    82  	} else {
    83  		grubFile.Contents = grubFile.Contents + "\n" + newLine + "\n"
    84  	}
    85  }
    86  
    87  func (grubFile *grubFile) GetMenuEntries() []MenuEntry {
    88  	menuEntries := []MenuEntry{}
    89  	Contents := grubFile.Contents
    90  	index := strings.Index(Contents, "\nmenuentry")
    91  	for index >= 0 {
    92  		Contents = Contents[index+len("\nmenuentry"):]
    93  		startIdx := strings.Index(Contents, "{\n")
    94  		endIdx := strings.Index(Contents, "\n}")
    95  		split := strings.Fields(Contents[:startIdx])
    96  		newEntry := MenuEntry{
    97  			Name:     split[0],
    98  			Options:  strings.TrimSpace(Contents[strings.Index(Contents, split[0])+len(split[0]) : startIdx]),
    99  			Contents: strings.Split(Contents[startIdx+2:endIdx], "\n"),
   100  		}
   101  		Contents = Contents[endIdx:]
   102  
   103  		menuEntries = append(menuEntries, newEntry)
   104  		index = strings.Index(Contents, "\nmenuentry")
   105  	}
   106  	return menuEntries
   107  }
   108  
   109  func (grubFile *grubFile) GetMenuEntry(name string) (*MenuEntry, error) {
   110  	for _, entry := range grubFile.GetMenuEntries() {
   111  		if strings.HasPrefix(entry.Name, `"`+name) {
   112  			return &entry, nil
   113  		}
   114  	}
   115  	return nil, errors.New("Menu entry not found")
   116  }
   117  
   118  func (grubFile *grubFile) AddMenuEntry(menuEntry MenuEntry) {
   119  	grubFile.Contents += "\n\n" + menuEntry.String()
   120  }
   121  
   122  func (grubFile *grubFile) DeleteMenuEntry(entryName string) {
   123  	re := regexp.MustCompile(`\n*menuentry\s+.?` + entryName + `.?\s+(.|\n)*\n}`)
   124  	grubFile.Contents = re.ReplaceAllString(grubFile.Contents, "")
   125  }
   126  
   127  func (menuEntry *MenuEntry) String() string {
   128  	str := fmt.Sprintf("menuentry %s %s {", menuEntry.Name, menuEntry.Options)
   129  	for _, x := range menuEntry.Contents {
   130  		str += "\n" + x
   131  	}
   132  	str += "\n}"
   133  	return str
   134  }
   135  

View as plain text