github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/exp/dmidecode/dmidecode.go (about) 1 // Copyright 2016-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 main 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 "strconv" 12 "strings" 13 14 flag "github.com/spf13/pflag" 15 16 "github.com/u-root/u-root/pkg/smbios" 17 ) 18 19 var ( 20 flagDumpBin = flag.String("dump-bin", "", `Do not decode the entries, instead dump the DMI data to a file in binary form. The generated file is suitable to pass to --from-dump later.`) 21 flagFromDump = flag.String("from-dump", "", `Read the DMI data from a binary file previously generated using --dump-bin.`) 22 flagType = flag.StringSliceP("type", "t", nil, `Only display the entries of type TYPE. TYPE can be either a DMI type number, or a comma-separated list of type numbers, or a keyword from the following list: bios, system, baseboard, chassis, processor, memory, cache, connector, slot. If this option is used more than once, the set of displayed entries will be the union of all the given types. If TYPE is not provided or not valid, a list of all valid keywords is printed and dmidecode exits with an error.`) 23 // NB: When adding flags, update resetFlags in dmidecode_test. 24 ) 25 26 var ( 27 typeGroups = map[string][]uint8{ 28 "bios": {0, 13}, 29 "system": {1, 12, 15, 23, 32}, 30 "baseboard": {2, 10, 41}, 31 "chassis": {3}, 32 "processor": {4}, 33 "memory": {5, 6, 16, 17}, 34 "cache": {7}, 35 "connector": {8}, 36 "slot": {9}, 37 } 38 ) 39 40 type dmiDecodeError struct { 41 error 42 code int 43 } 44 45 // parseTypeFilter parses the --type argument(s) and returns a set of types taht should be included. 46 func parseTypeFilter(typeStrings []string) (map[smbios.TableType]bool, error) { 47 types := map[smbios.TableType]bool{} 48 for _, ts := range typeStrings { 49 if tg, ok := typeGroups[strings.ToLower(ts)]; ok { 50 for _, t := range tg { 51 types[smbios.TableType(t)] = true 52 } 53 } else { 54 u, err := strconv.ParseUint(ts, 0, 8) 55 if err != nil { 56 return nil, fmt.Errorf("Invalid type: %s", ts) 57 } 58 types[smbios.TableType(uint8(u))] = true 59 } 60 } 61 return types, nil 62 } 63 64 func dumpBin(textOut io.Writer, entryData, tableData []byte, fileName string) *dmiDecodeError { 65 // Need to rewrite address to be compatible with dmidecode(8). 66 e32, e64, err := smbios.ParseEntry(entryData) 67 if err != nil { 68 return &dmiDecodeError{code: 1, error: fmt.Errorf("error parsing entry point structure: %v", err)} 69 } 70 var edata []byte 71 switch { 72 case e32 != nil: 73 e32.StructTableAddr = 0x20 74 edata, _ = e32.MarshalBinary() 75 case e64 != nil: 76 e64.StructTableAddr = 0x20 77 edata, _ = e64.MarshalBinary() 78 } 79 f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644) 80 if err != nil { 81 return &dmiDecodeError{code: 1, error: fmt.Errorf("error opening file for writing: %v", err)} 82 } 83 defer f.Close() 84 fmt.Fprintf(textOut, "# Writing %d bytes to %s.\n", len(edata), fileName) 85 if _, err := f.Write(edata); err != nil { 86 return &dmiDecodeError{code: 1, error: fmt.Errorf("error writing entry: %v", err)} 87 } 88 for i := len(edata); i < 0x20; i++ { 89 if _, err := f.Write([]byte{0}); err != nil { 90 return &dmiDecodeError{code: 1, error: fmt.Errorf("error writing entry: %v", err)} 91 } 92 } 93 fmt.Fprintf(textOut, "# Writing %d bytes to %s.\n", len(tableData), fileName) 94 if _, err := f.Write(tableData); err != nil { 95 return &dmiDecodeError{code: 1, error: fmt.Errorf("error writing table data: %v", err)} 96 } 97 return nil 98 } 99 100 func dmiDecode(textOut io.Writer) *dmiDecodeError { 101 typeFilter, err := parseTypeFilter(*flagType) 102 if err != nil { 103 return &dmiDecodeError{code: 2, error: fmt.Errorf("invalid --type: %v", err)} 104 } 105 fmt.Fprintf(textOut, "# dmidecode-go\n") // TODO: version. 106 entryData, tableData, err := getData(textOut, *flagFromDump, "/sys/firmware/dmi/tables") 107 if err != nil { 108 return &dmiDecodeError{code: 1, error: fmt.Errorf("error parsing loading data: %v", err)} 109 } 110 if *flagDumpBin != "" { 111 return dumpBin(textOut, entryData, tableData, *flagDumpBin) 112 } 113 si, err := smbios.ParseInfo(entryData, tableData) 114 if err != nil { 115 return &dmiDecodeError{code: 1, error: fmt.Errorf("error parsing data: %v", err)} 116 } 117 if si.Entry64 != nil { 118 fmt.Fprintf(textOut, "SMBIOS %d.%d.%d present.\n", si.MajorVersion(), si.MinorVersion(), si.DocRev()) 119 } else { 120 fmt.Fprintf(textOut, "SMBIOS %d.%d present.\n", si.MajorVersion(), si.MinorVersion()) 121 } 122 if si.Entry32 != nil { 123 fmt.Fprintf(textOut, "%d structures occupying %d bytes.\n", si.Entry32.NumberOfStructs, si.Entry32.StructTableLength) 124 } 125 fmt.Fprintf(textOut, "\n") 126 for _, t := range si.Tables { 127 if len(typeFilter) != 0 && !typeFilter[t.Type] { 128 continue 129 } 130 pt, err := smbios.ParseTypedTable(t) 131 if err != nil { 132 if err != smbios.ErrUnsupportedTableType { 133 fmt.Fprintf(os.Stderr, "%s\n", err) 134 } 135 // Print as raw table 136 pt = t 137 } 138 fmt.Fprintf(textOut, "%s\n\n", pt) 139 } 140 return nil 141 } 142 143 func main() { 144 flag.Parse() 145 err := dmiDecode(os.Stdout) 146 if err != nil { 147 fmt.Fprintf(os.Stderr, "%s\n", err) 148 os.Exit(err.code) 149 } 150 }