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