github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/grub/entry.go (about)

     1  // Copyright 2020 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package grub
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"fmt"
    11  	"io"
    12  	"sort"
    13  	"strings"
    14  )
    15  
    16  // GRUB block size.
    17  const blockSize = 1024
    18  
    19  // EnvFile is a GRUB environment file consisting of key-value pairs akin to the
    20  // GRUB commands load_env and save_env.
    21  type EnvFile struct {
    22  	Vars map[string]string
    23  }
    24  
    25  // NewEnvFile allocates a new env file.
    26  func NewEnvFile() *EnvFile {
    27  	return &EnvFile{
    28  		Vars: make(map[string]string),
    29  	}
    30  }
    31  
    32  // WriteTo writes key-value pairs to a file, padded to 1024 bytes, as save_env does.
    33  func (env *EnvFile) WriteTo(w io.Writer) (int64, error) {
    34  	var b bytes.Buffer
    35  	b.WriteString("# GRUB Environment Block\n")
    36  
    37  	// Sort keys so order is deterministic.
    38  	keys := make([]string, 0, len(env.Vars))
    39  	for k := range env.Vars {
    40  		keys = append(keys, k)
    41  	}
    42  	sort.Strings(keys)
    43  
    44  	for _, k := range keys {
    45  		if len(env.Vars[k]) > 0 {
    46  			b.WriteString(k)
    47  			b.WriteString("=")
    48  			b.WriteString(env.Vars[k])
    49  			b.WriteString("\n")
    50  		}
    51  	}
    52  	length := b.Len()
    53  
    54  	// Fill up the file with # until 1024 bytes to make the file size a
    55  	// multiple of the block size.
    56  	remainder := blockSize - length%blockSize
    57  	for i := 0; i < remainder; i++ {
    58  		b.WriteByte('#')
    59  	}
    60  
    61  	return b.WriteTo(w)
    62  }
    63  
    64  // ParseEnvFile reads a key-value pair GRUB environment file.
    65  //
    66  // ParseEnvFile accepts incorrectly padded GRUB env files, as opposed to GRUB.
    67  func ParseEnvFile(r io.Reader) (*EnvFile, error) {
    68  	s := bufio.NewScanner(r)
    69  	conf := NewEnvFile()
    70  	// Best lexer & parser in the world.
    71  	for s.Scan() {
    72  		if len(s.Text()) == 0 {
    73  			continue
    74  		}
    75  		// Comments.
    76  		if s.Text()[0] == '#' {
    77  			continue
    78  		}
    79  
    80  		tokens := strings.SplitN(s.Text(), "=", 2)
    81  		if len(tokens) != 2 {
    82  			return nil, fmt.Errorf("error parsing %q: must find = or # in each line", s.Text())
    83  		}
    84  		key, value := tokens[0], tokens[1]
    85  		conf.Vars[key] = value
    86  	}
    87  	if err := s.Err(); err != nil {
    88  		return nil, err
    89  	}
    90  	return conf, nil
    91  }