Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

11
vendor/github.com/digitalocean/go-smbios/AUTHORS generated vendored Normal file
View File

@@ -0,0 +1,11 @@
Maintainer
----------
DigitalOcean, Inc
Original Authors
----------------
Matt Layher <mlayher@digitalocean.com>
Contributors
------------
Christopher Dudley <chris@terainsights.com>

195
vendor/github.com/digitalocean/go-smbios/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
_END OF TERMS AND CONDITIONS_
### APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,231 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package smbios
import (
"bufio"
"bytes"
"encoding/binary"
"io"
)
const (
// headerLen is the length of the Header structure.
headerLen = 4
// typeEndOfTable indicates the end of a stream of Structures.
typeEndOfTable = 127
)
var (
// Byte slices used to help parsing string-sets.
null = []byte{0x00}
endStringSet = []byte{0x00, 0x00}
)
// A Decoder decodes Structures from a stream.
type Decoder struct {
br *bufio.Reader
b []byte
}
// Stream locates and opens a stream of SMBIOS data and the SMBIOS entry
// point from an operating system-specific location. The stream must be
// closed after decoding to free its resources.
//
// If no suitable location is found, an error is returned.
func Stream() (io.ReadCloser, EntryPoint, error) {
rc, ep, err := stream()
if err != nil {
return nil, nil, err
}
// The io.ReadCloser from stream could be any one of a number of types
// depending on the source of the SMBIOS stream information.
//
// To prevent the caller from potentially tampering with something dangerous
// like mmap'd memory by using a type assertion, we make the io.ReadCloser
// into an opaque and unexported type to prevent type assertion.
return &opaqueReadCloser{rc: rc}, ep, nil
}
// NewDecoder creates a Decoder which decodes Structures from the input stream.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
br: bufio.NewReader(r),
b: make([]byte, 1024),
}
}
// Decode decodes Structures from the Decoder's stream until an End-of-table
// structure is found.
func (d *Decoder) Decode() ([]*Structure, error) {
var ss []*Structure
for {
s, err := d.next()
if err != nil {
return nil, err
}
// End-of-table structure indicates end of stream.
ss = append(ss, s)
if s.Header.Type == typeEndOfTable {
break
}
}
return ss, nil
}
// next decodes the next Structure from the stream.
func (d *Decoder) next() (*Structure, error) {
h, err := d.parseHeader()
if err != nil {
return nil, err
}
// Length of formatted section is length specified by header, minus
// the length of the header itself.
l := int(h.Length) - headerLen
fb, err := d.parseFormatted(l)
if err != nil {
return nil, err
}
ss, err := d.parseStrings()
if err != nil {
return nil, err
}
return &Structure{
Header: *h,
Formatted: fb,
Strings: ss,
}, nil
}
// parseHeader parses a Structure's Header from the stream.
func (d *Decoder) parseHeader() (*Header, error) {
if _, err := io.ReadFull(d.br, d.b[:headerLen]); err != nil {
return nil, err
}
return &Header{
Type: d.b[0],
Length: d.b[1],
Handle: binary.LittleEndian.Uint16(d.b[2:4]),
}, nil
}
// parseFormatted parses a Structure's formatted data from the stream.
func (d *Decoder) parseFormatted(l int) ([]byte, error) {
// Guard against malformed input length.
if l < 0 {
return nil, io.ErrUnexpectedEOF
}
if l == 0 {
// No formatted data.
return nil, nil
}
if _, err := io.ReadFull(d.br, d.b[:l]); err != nil {
return nil, err
}
// Make a copy to free up the internal buffer.
fb := make([]byte, len(d.b[:l]))
copy(fb, d.b[:l])
return fb, nil
}
// parseStrings parses a Structure's strings from the stream, if they
// are present.
func (d *Decoder) parseStrings() ([]string, error) {
term, err := d.br.Peek(2)
if err != nil {
return nil, err
}
// If no string-set present, discard delimeter and end parsing.
if bytes.Equal(term, endStringSet) {
if _, err := d.br.Discard(2); err != nil {
return nil, err
}
return nil, nil
}
var ss []string
for {
s, more, err := d.parseString()
if err != nil {
return nil, err
}
// When final string is received, end parse loop.
ss = append(ss, s)
if !more {
break
}
}
return ss, nil
}
// parseString parses a single string from the stream, and returns if
// any more strings are present.
func (d *Decoder) parseString() (str string, more bool, err error) {
// We initially read bytes because it's more efficient to manipulate bytes
// and allocate a string once we're all done.
//
// Strings are null-terminated.
raw, err := d.br.ReadBytes(0x00)
if err != nil {
return "", false, err
}
b := bytes.TrimRight(raw, "\x00")
peek, err := d.br.Peek(1)
if err != nil {
return "", false, err
}
if !bytes.Equal(peek, null) {
// Next byte isn't null; more strings to come.
return string(b), true, nil
}
// If two null bytes appear in a row, end of string-set.
// Discard the null and indicate no more strings.
if _, err := d.br.Discard(1); err != nil {
return "", false, err
}
return string(b), false, nil
}
var _ io.ReadCloser = &opaqueReadCloser{}
// An opaqueReadCloser masks the type of the underlying io.ReadCloser to
// prevent type assertions.
type opaqueReadCloser struct {
rc io.ReadCloser
}
func (rc *opaqueReadCloser) Read(b []byte) (int, error) { return rc.rc.Read(b) }
func (rc *opaqueReadCloser) Close() error { return rc.rc.Close() }

17
vendor/github.com/digitalocean/go-smbios/smbios/doc.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package smbios provides detection and access to System Management BIOS (SMBIOS)
// and Desktop Management Interface (DMI) data and structures.
package smbios

View File

@@ -0,0 +1,267 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package smbios
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
)
// Anchor strings used to detect entry points.
var (
// Used when searching for an entry point in memory.
magicPrefix = []byte("_SM")
// Used to determine specific entry point types.
magic32 = []byte("_SM_")
magic64 = []byte("_SM3_")
magicDMI = []byte("_DMI_")
)
// An EntryPoint is an SMBIOS entry point. EntryPoints contain various
// properties about SMBIOS.
//
// Use a type assertion to access detailed EntryPoint information.
type EntryPoint interface {
// Table returns the memory address and maximum size of the SMBIOS table.
Table() (address, size int)
// Version returns the system's SMBIOS version.
Version() (major, minor, revision int)
}
// ParseEntryPoint parses an EntryPoint from the input stream.
func ParseEntryPoint(r io.Reader) (EntryPoint, error) {
// Prevent unbounded reads since this structure should be small.
b, err := ioutil.ReadAll(io.LimitReader(r, 64))
if err != nil {
return nil, err
}
if l := len(b); l < 4 {
return nil, fmt.Errorf("too few bytes for SMBIOS entry point magic: %d", l)
}
switch {
case bytes.HasPrefix(b, magic32):
return parse32(b)
case bytes.HasPrefix(b, magic64):
return parse64(b)
}
return nil, fmt.Errorf("unrecognized SMBIOS entry point magic: %v", b[0:4])
}
var _ EntryPoint = &EntryPoint32Bit{}
// EntryPoint32Bit is the SMBIOS 32-bit Entry Point structure, used starting
// in SMBIOS 2.1.
type EntryPoint32Bit struct {
Anchor string
Checksum uint8
Length uint8
Major uint8
Minor uint8
MaxStructureSize uint16
EntryPointRevision uint8
FormattedArea [5]byte
IntermediateAnchor string
IntermediateChecksum uint8
StructureTableLength uint16
StructureTableAddress uint32
NumberStructures uint16
BCDRevision uint8
}
// Table implements EntryPoint.
func (e *EntryPoint32Bit) Table() (address, size int) {
return int(e.StructureTableAddress), int(e.StructureTableLength)
}
// Version implements EntryPoint.
func (e *EntryPoint32Bit) Version() (major, minor, revision int) {
return int(e.Major), int(e.Minor), 0
}
// parse32 parses an EntryPoint32Bit from b.
func parse32(b []byte) (*EntryPoint32Bit, error) {
l := len(b)
// Correct minimum length as of SMBIOS 3.1.1.
const expLen = 31
if l < expLen {
return nil, fmt.Errorf("expected SMBIOS 32-bit entry point minimum length of at least %d, but got: %d", expLen, l)
}
// Allow more data in the buffer than the actual length, for when the
// entry point is being read from system memory.
length := b[5]
if l < int(length) {
return nil, fmt.Errorf("expected SMBIOS 32-bit entry point actual length of at least %d, but got: %d", length, l)
}
// Look for intermediate anchor with DMI magic.
iAnchor := b[16:21]
if !bytes.Equal(iAnchor, magicDMI) {
return nil, fmt.Errorf("incorrect DMI magic in SMBIOS 32-bit entry point: %v", iAnchor)
}
// Entry point checksum occurs at index 4, compute and verify it.
const epChkIndex = 4
epChk := b[epChkIndex]
if err := checksum(epChk, epChkIndex, b[:length]); err != nil {
return nil, err
}
// Since we already computed the checksum for the outer entry point,
// no real need to compute it for the intermediate entry point.
ep := &EntryPoint32Bit{
Anchor: string(b[0:4]),
Checksum: epChk,
Length: length,
Major: b[6],
Minor: b[7],
MaxStructureSize: binary.LittleEndian.Uint16(b[8:10]),
EntryPointRevision: b[10],
IntermediateAnchor: string(iAnchor),
IntermediateChecksum: b[21],
StructureTableLength: binary.LittleEndian.Uint16(b[22:24]),
StructureTableAddress: binary.LittleEndian.Uint32(b[24:28]),
NumberStructures: binary.LittleEndian.Uint16(b[28:30]),
BCDRevision: b[30],
}
copy(ep.FormattedArea[:], b[10:15])
return ep, nil
}
var _ EntryPoint = &EntryPoint64Bit{}
// EntryPoint64Bit is the SMBIOS 64-bit Entry Point structure, used starting
// in SMBIOS 3.0.
type EntryPoint64Bit struct {
Anchor string
Checksum uint8
Length uint8
Major uint8
Minor uint8
Revision uint8
EntryPointRevision uint8
Reserved uint8
StructureTableMaxSize uint32
StructureTableAddress uint64
}
// Table implements EntryPoint.
func (e *EntryPoint64Bit) Table() (address, size int) {
return int(e.StructureTableAddress), int(e.StructureTableMaxSize)
}
// Version implements EntryPoint.
func (e *EntryPoint64Bit) Version() (major, minor, revision int) {
return int(e.Major), int(e.Minor), int(e.Revision)
}
const (
// expLen64 is the expected minimum length of a 64-bit entry point.
// Correct minimum length as of SMBIOS 3.1.1.
expLen64 = 24
// chkIndex64 is the index of the checksum byte in a 64-bit entry point.
chkIndex64 = 5
)
// parse64 parses an EntryPoint64Bit from b.
func parse64(b []byte) (*EntryPoint64Bit, error) {
l := len(b)
// Ensure expected minimum length.
if l < expLen64 {
return nil, fmt.Errorf("expected SMBIOS 64-bit entry point minimum length of at least %d, but got: %d", expLen64, l)
}
// Allow more data in the buffer than the actual length, for when the
// entry point is being read from system memory.
length := b[6]
if l < int(length) {
return nil, fmt.Errorf("expected SMBIOS 64-bit entry point actual length of at least %d, but got: %d", length, l)
}
// Checksum occurs at index 5, compute and verify it.
chk := b[chkIndex64]
if err := checksum(chk, chkIndex64, b); err != nil {
return nil, err
}
return &EntryPoint64Bit{
Anchor: string(b[0:5]),
Checksum: chk,
Length: length,
Major: b[7],
Minor: b[8],
Revision: b[9],
EntryPointRevision: b[10],
Reserved: b[11],
StructureTableMaxSize: binary.LittleEndian.Uint32(b[12:16]),
StructureTableAddress: binary.LittleEndian.Uint64(b[16:24]),
}, nil
}
// checksum computes the checksum of b using the starting value of start, and
// skipping the checksum byte which occurs at index chkIndex.
//
// checksum assumes that b has already had its bounds checked.
func checksum(start uint8, chkIndex int, b []byte) error {
chk := start
for i := range b {
// Checksum computation does not include index of checksum byte.
if i == chkIndex {
continue
}
chk += b[i]
}
if chk != 0 {
return fmt.Errorf("invalid entry point checksum %#02x from initial checksum %#02x", chk, start)
}
return nil
}
// WindowsEntryPoint contains SMBIOS Table entry point data returned from
// GetSystemFirmwareTable. As raw access to the underlying memory is not given,
// the full breadth of information is not available.
type WindowsEntryPoint struct {
Size uint32
MajorVersion byte
MinorVersion byte
Revision byte
}
// Table implements EntryPoint. The returned address will always be 0, as it
// is not returned by GetSystemFirmwareTable.
func (e *WindowsEntryPoint) Table() (address, size int) {
return 0, int(e.Size)
}
// Version implements EntryPoint.
func (e *WindowsEntryPoint) Version() (major, minor, revision int) {
return int(e.MajorVersion), int(e.MinorVersion), int(e.Revision)
}

View File

@@ -0,0 +1,35 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//+build gofuzz
package smbios
import (
"bytes"
)
func Fuzz(data []byte) int {
return fuzzDecoder(data)
}
func fuzzDecoder(data []byte) int {
d := NewDecoder(bytes.NewReader(data))
if _, err := d.Decode(); err != nil {
return 0
}
return 1
}

View File

@@ -0,0 +1,65 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//+build linux
package smbios
import (
"io"
"os"
)
const (
// sysfs locations for SMBIOS information.
sysfsDMI = "/sys/firmware/dmi/tables/DMI"
sysfsEntryPoint = "/sys/firmware/dmi/tables/smbios_entry_point"
)
// stream opens the SMBIOS entry point and an SMBIOS structure stream.
func stream() (io.ReadCloser, EntryPoint, error) {
// First, check for the sysfs location present in modern kernels.
_, err := os.Stat(sysfsEntryPoint)
switch {
case err == nil:
return sysfsStream(sysfsEntryPoint, sysfsDMI)
case os.IsNotExist(err):
// Fall back to the standard UNIX-like system method.
return devMemStream()
default:
return nil, nil, err
}
}
// sysfsStream reads the SMBIOS entry point and structure stream from
// two files; usually the modern sysfs locations.
func sysfsStream(entryPoint, dmi string) (io.ReadCloser, EntryPoint, error) {
epf, err := os.Open(entryPoint)
if err != nil {
return nil, nil, err
}
defer epf.Close()
ep, err := ParseEntryPoint(epf)
if err != nil {
return nil, nil, err
}
sf, err := os.Open(dmi)
if err != nil {
return nil, nil, err
}
return sf, ep, nil
}

View File

@@ -0,0 +1,125 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package smbios
import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
)
const (
// devMem is the UNIX-like system memory device location used to
// find SMBIOS information.
devMem = "/dev/mem"
// SMBIOS specification indicates that the entry point should exist
// between these two memory addresses.
startAddr = 0x000f0000
endAddr = 0x000fffff
)
// memoryStream reads the SMBIOS entry point and structure stream from
// an io.ReadSeeker (usually system memory).
//
// memoryStream is an entry point for tests.
func memoryStream(rs io.ReadSeeker, startAddr, endAddr int) (io.ReadCloser, EntryPoint, error) {
// Try to find the entry point.
addr, err := findEntryPoint(rs, startAddr, endAddr)
if err != nil {
return nil, nil, err
}
// Found it; seek to the location of the entry point.
if _, err := rs.Seek(int64(addr), io.SeekStart); err != nil {
return nil, nil, err
}
// Read the entry point and determine where the SMBIOS table is.
ep, err := ParseEntryPoint(rs)
if err != nil {
return nil, nil, err
}
// Seek to the start of the SMBIOS table.
tableAddr, tableSize := ep.Table()
if _, err := rs.Seek(int64(tableAddr), io.SeekStart); err != nil {
return nil, nil, err
}
// Make a copy of the memory so we don't return a handle to system memory
// to the caller.
out := make([]byte, tableSize)
if _, err := io.ReadFull(rs, out); err != nil {
return nil, nil, err
}
return ioutil.NopCloser(bytes.NewReader(out)), ep, nil
}
// findEntryPoint attempts to locate the entry point structure in the io.ReadSeeker
// using the start and end bound as hints for its location.
func findEntryPoint(rs io.ReadSeeker, start, end int) (int, error) {
// Begin searching at the start bound.
if _, err := rs.Seek(int64(start), io.SeekStart); err != nil {
return 0, err
}
// Iterate one "paragraph" of memory at a time until we either find the entry point
// or reach the end bound.
const paragraph = 16
b := make([]byte, paragraph)
var (
addr int
found bool
)
for addr = start; addr < end; addr += paragraph {
if _, err := io.ReadFull(rs, b); err != nil {
return 0, err
}
// Both the 32-bit and 64-bit entry point have a similar prefix.
if bytes.HasPrefix(b, magicPrefix) {
found = true
break
}
}
if !found {
return 0, errors.New("no SMBIOS entry point found in memory")
}
// Return the exact memory location of the entry point.
return addr, nil
}
// devMemStream reads the SMBIOS entry point and structure stream from
// the UNIX-like system /dev/mem device.
//
// This is UNIX-like system specific, but since it doesn't employ any system
// calls or OS-dependent constants, it remains in this file for simplicity.
func devMemStream() (io.ReadCloser, EntryPoint, error) {
mem, err := os.Open(devMem)
if err != nil {
return nil, nil, err
}
defer mem.Close()
return memoryStream(mem, startAddr, endAddr)
}

View File

@@ -0,0 +1,28 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//+build !dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package smbios
import (
"fmt"
"io"
"runtime"
)
// stream is not implemented for unsupported platforms.
func stream() (io.ReadCloser, EntryPoint, error) {
return nil, nil, fmt.Errorf("opening SMBIOS stream not implemented on %q", runtime.GOOS)
}

View File

@@ -0,0 +1,30 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//+build dragonfly freebsd netbsd openbsd solaris
// Linux intentionally omitted because it has an alternative method that
// is used before attempting /dev/mem access. See stream_linux.go.
package smbios
import (
"io"
)
// stream opens the SMBIOS entry point and an SMBIOS structure stream.
func stream() (io.ReadCloser, EntryPoint, error) {
// Use the standard UNIX-like system method.
return devMemStream()
}

View File

@@ -0,0 +1,155 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package smbios
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"syscall"
"unsafe"
)
// firmwareTableProviderSigRSMB is the identifier for the raw SMBIOS firmware table
// provider.
// It is equal to the ASCII characters 'RSMB' packed into a uint32.
// In the C++ example code in the MSDN documentation, this is specified using
// multi-byte character literals, which are automatically coerced to an integer by
// the C++ compiler.
const firmwareTableProviderSigRSMB uint32 = 0x52534d42
// smbiosDataHeaderSize is size of the "header" (non-variable) part of the
// RawSMBIOSData struct. This serves as both the offset to the actual
// SMBIOS table data, and the minimum possible size of a valid RawSMBIOSDATA
// struct (with a table length of 0).
const rawSMBIOSDataHeaderSize = 8
var (
libKernel32 = syscall.NewLazyDLL("kernel32.dll")
// MSDN Documentation for GetSystemFirmwareTable:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724379(v=vs.85).aspx
procGetSystemFirmwareTable = libKernel32.NewProc("GetSystemFirmwareTable")
)
// nativeEndian returns the native byte order of this system.
func nativeEndian() binary.ByteOrder {
// Determine endianness by interpreting a uint16 as a byte slice.
v := uint16(1)
b := *(*[2]byte)(unsafe.Pointer(&v))
if b[0] == 1 {
return binary.LittleEndian
}
return binary.BigEndian
}
// windowsStream parses the data returned from GetSystemFirmwareTable('RSMB',...)
// and returns a stream and entrypoint that can be used to decode the system's
// SMBIOS table.
//
// When calling GetSystemFirmwareTable with FirmwareTableProviderSignature = "RSMB",
// Windows will write a RawSMBIOSData struct into the output buffer.
// Thus, `buf` is expected to contain a valid RawSMBIOSData structure.
//
// From windows.h:
//
// struct RawSMBIOSData {
// BYTE Used20CallingMethod;
// BYTE SMBIOSMajorVersion;
// BYTE SMBIOSMinorVersion;
// BYTE DMIRevision;
// DWORD Length;
// BYTE SMBIOSTableData[];
// }
//
// Note: a DWORD is equivalent to a uint32
// See: https://msdn.microsoft.com/en-us/library/cc230318.aspx
func windowsStream(buf []byte) (io.ReadCloser, EntryPoint, error) {
bufLen := uint32(len(buf))
// Do an additional check to make sure the actual amount written is sane.
if bufLen < rawSMBIOSDataHeaderSize {
return nil, nil, fmt.Errorf("GetSystemFirmwareTable wrote less data than expected: wrote %d bytes, expected at least 8 bytes", bufLen)
}
tableSize := nativeEndian().Uint32(buf[4:8])
if rawSMBIOSDataHeaderSize+tableSize > bufLen {
return nil, nil, errors.New("reported SMBIOS table size exceeds buffer")
}
entryPoint := &WindowsEntryPoint{
MajorVersion: buf[1],
MinorVersion: buf[2],
Revision: buf[3],
Size: tableSize,
}
tableBuff := buf[rawSMBIOSDataHeaderSize : rawSMBIOSDataHeaderSize+tableSize]
return ioutil.NopCloser(bytes.NewReader(tableBuff)), entryPoint, nil
}
func stream() (io.ReadCloser, EntryPoint, error) {
// Call first with empty buffer to get size.
r1, _, err := procGetSystemFirmwareTable.Call(
uintptr(firmwareTableProviderSigRSMB), // FirmwareTableProviderSignature = 'RSMB'
0, // FirmwareTableID = 0
0, // pFirmwareTableBuffer = NULL
0, // BufferSize = 0
)
// LazyProc.Call will always return err != nil, so we need to check the primary
// return value (r1) to determine whether or not an error occurred.
// In this case, r1 should contain the size of the needed buffer, so it will only
// be 0 if the function call failed for some reason.
//
// Godoc for LazyProc.Call:
// https://golang.org/pkg/syscall/?GOOS=windows&GOARCH=amd64#LazyProc.Call
if r1 == 0 {
return nil, nil, fmt.Errorf("failed to determine size of buffer needed: %v", err)
}
if r1 < rawSMBIOSDataHeaderSize {
return nil, nil, fmt.Errorf("reported buffer size smaller than expected: reported %d, expected >= 8", r1)
}
bufferSize := uint32(r1)
buffer := make([]byte, bufferSize)
r1, _, err = procGetSystemFirmwareTable.Call(
uintptr(firmwareTableProviderSigRSMB), // FirmwareTableProviderSignature = 'RSMB'
0, // FirmwareTableID = 0
uintptr(unsafe.Pointer(&buffer[0])), // pFirmwareTableBuffer = &buffer
uintptr(bufferSize), // BufferSize = bufferSize
)
bytesWritten := uint32(r1)
// Check for the two possible failure cases documented in API:
if bytesWritten > bufferSize {
return nil, nil, fmt.Errorf("buffer size was too small, somehow: have %d bytes, Windows wanted %d bytes", bufferSize, bytesWritten)
}
if bytesWritten == 0 {
return nil, nil, fmt.Errorf("failed to read SMBIOS data: %v", err)
}
// At this point, bytesWritten <= bufferSize, which means the call succeeded as
// per the MSDN documentation.
return windowsStream(buffer[:bytesWritten])
}

View File

@@ -0,0 +1,29 @@
// Copyright 2017-2018 DigitalOcean.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package smbios
// A Header is a Structure's header.
type Header struct {
Type uint8
Length uint8
Handle uint16
}
// A Structure is an SMBIOS structure.
type Structure struct {
Header Header
Formatted []byte
Strings []string
}