github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/uefivars/vars.go (about) 1 // Copyright 2015-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 // SPDX-License-Identifier: BSD-3-Clause 6 // 7 8 package uefivars 9 10 import ( 11 "bytes" 12 "fmt" 13 "io/ioutil" 14 "log" 15 "os" 16 fp "path/filepath" 17 "strings" 18 "unicode/utf16" 19 "unicode/utf8" 20 ) 21 22 //http://kurtqiao.github.io/uefi/2015/01/13/uefi-boot-manager.html 23 24 //overridden for testing 25 var EfiVarDir = "/sys/firmware/efi/vars" 26 27 //EfiVar is a generic efi var 28 type EfiVar struct { 29 Uuid, Name string 30 Data []byte 31 } 32 type EfiVars []EfiVar 33 34 func ReadVar(uuid, name string) (e EfiVar, err error) { 35 path := fp.Join(EfiVarDir, name+"-"+uuid, "data") 36 e.Uuid = uuid 37 e.Name = name 38 e.Data, err = ioutil.ReadFile(path) 39 return 40 } 41 42 // AllVars returns all efi variables 43 func AllVars() (vars EfiVars) { return ReadVars(nil) } 44 45 // ReadVars returns efi variables matching filter 46 func ReadVars(filt VarFilter) (vars EfiVars) { 47 entries, err := fp.Glob(fp.Join(EfiVarDir, "*-*")) 48 if err != nil { 49 log.Printf("error reading efi vars: %s", err) 50 return 51 } 52 for _, entry := range entries { 53 base := fp.Base(entry) 54 n := strings.Count(base, "-") 55 if n < 5 { 56 log.Printf("skipping %s - not a valid var?", base) 57 continue 58 } 59 components := strings.SplitN(base, "-", 2) 60 if filt != nil && !filt(components[1], components[0]) { 61 continue 62 } 63 info, err := os.Stat(entry) 64 if err == nil && info.IsDir() { 65 v, err := ReadVar(components[1], components[0]) 66 if err != nil { 67 log.Printf("reading efi var %s: %s", base, err) 68 continue 69 } 70 vars = append(vars, v) 71 } 72 } 73 return 74 } 75 76 // VarFilter is a type of function used to filter efi vars 77 type VarFilter func(uuid, name string) bool 78 79 // NotFilter returns a filter negating the given filter. 80 func NotFilter(f VarFilter) VarFilter { 81 return func(u, n string) bool { return !f(u, n) } 82 } 83 84 // AndFilter returns true only if all given filters return true. 85 func AndFilter(filters ...VarFilter) VarFilter { 86 return func(u, n string) bool { 87 for _, f := range filters { 88 if !f(u, n) { 89 return false 90 } 91 } 92 return true 93 } 94 } 95 96 // Filter returns the elements of the list for which the filter function 97 // returns true. 98 func (vars EfiVars) Filter(filt VarFilter) EfiVars { 99 var res EfiVars 100 for _, v := range vars { 101 if filt(v.Uuid, v.Name) { 102 res = append(res, v) 103 } 104 } 105 return res 106 } 107 108 // DecodeUTF16 decodes the input as a utf16 string. 109 // https://gist.github.com/bradleypeabody/185b1d7ed6c0c2ab6cec 110 func DecodeUTF16(b []byte) (string, error) { 111 if len(b)%2 != 0 { 112 return "", fmt.Errorf("Must have even length byte slice") 113 } 114 115 u16s := make([]uint16, 1) 116 ret := &bytes.Buffer{} 117 b8buf := make([]byte, 4) 118 119 lb := len(b) 120 for i := 0; i < lb; i += 2 { 121 u16s[0] = BytesToU16(b[i : i+2]) 122 r := utf16.Decode(u16s) 123 n := utf8.EncodeRune(b8buf, r[0]) 124 ret.Write(b8buf[:n]) 125 } 126 127 return ret.String(), nil 128 } 129 130 // BytesToU16 converts a []byte of length 2 to a uint16. 131 func BytesToU16(b []byte) uint16 { 132 if len(b) != 2 { 133 log.Fatalf("bytesToU16: bad len %d (%x)", len(b), b) 134 } 135 return uint16(b[0]) + (uint16(b[1]) << 8) 136 }