github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/vpd/vpd.go (about)

     1  // Copyright 2017-2019 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 vpd
     6  
     7  import (
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  )
    12  
    13  // default variables
    14  var (
    15  	MaxBootEntry  = 9999
    16  	DefaultVpdDir = "/sys/firmware/vpd"
    17  )
    18  
    19  var globalReader = NewReader()
    20  
    21  // NewReader returns a new VPD Reader.
    22  func NewReader() *Reader {
    23  	return &Reader{
    24  		VpdDir: DefaultVpdDir,
    25  	}
    26  }
    27  
    28  // Get wraps globalReader.Get .
    29  func Get(key string, readOnly bool) ([]byte, error) {
    30  	return globalReader.Get(key, readOnly)
    31  }
    32  
    33  // Set wraps globalReader.Set .
    34  func Set(key string, value []byte, readOnly bool) error {
    35  	return globalReader.Set(key, value, readOnly)
    36  }
    37  
    38  // GetAll wraps globalReader.GetAll .
    39  func GetAll(readOnly bool) (map[string][]byte, error) {
    40  	return globalReader.GetAll(readOnly)
    41  }
    42  
    43  func (r *Reader) getBaseDir(readOnly bool) string {
    44  	if readOnly {
    45  		return path.Join(r.VpdDir, "ro")
    46  	}
    47  	return path.Join(r.VpdDir, "rw")
    48  }
    49  
    50  // Reader is a VPD reader object.
    51  type Reader struct {
    52  	VpdDir string
    53  }
    54  
    55  // Get reads a VPD variable by name and returns its value as a sequence of
    56  // bytes. The `readOnly` flag specifies whether the variable is read-only or
    57  // read-write.
    58  func (r *Reader) Get(key string, readOnly bool) ([]byte, error) {
    59  	buf, err := os.ReadFile(path.Join(r.getBaseDir(readOnly), key))
    60  	if err != nil {
    61  		return []byte{}, err
    62  	}
    63  	return buf, nil
    64  }
    65  
    66  // Set sets a VPD variable with `key` as name and `value` as its byte-stream
    67  // value. The `readOnly` flag specifies whether the variable is read-only or
    68  // read-write.
    69  // NOTE Unfortunately Set doesn't currently work, because the sysfs interface
    70  // does not support writing. To write, this library needs a backend able to
    71  // write to flash chips, like the command line tool flashrom or flashtools.
    72  func (r *Reader) Set(key string, value []byte, readOnly bool) error {
    73  	// NOTE this is not implemented yet in the kernel interface, and will always
    74  	// return a permission denied error
    75  	return os.WriteFile(path.Join(r.getBaseDir(readOnly), key), value, 0o644)
    76  }
    77  
    78  // GetAll reads all the VPD variables and returns a map contaiing each
    79  // name:value couple. The `readOnly` flag specifies whether the variable is
    80  // read-only or read-write.
    81  func (r *Reader) GetAll(readOnly bool) (map[string][]byte, error) {
    82  	vpdMap := make(map[string][]byte)
    83  	baseDir := r.getBaseDir(readOnly)
    84  	err := filepath.Walk(baseDir, func(fpath string, info os.FileInfo, _ error) error {
    85  		key := path.Base(fpath)
    86  		if key == "." || key == "/" || fpath == baseDir {
    87  			// empty or all slashes?
    88  			return nil
    89  		}
    90  		value, err := r.Get(key, readOnly)
    91  		if err != nil {
    92  			return err
    93  		}
    94  		vpdMap[key] = value
    95  		return nil
    96  	})
    97  	return vpdMap, err
    98  }