opendmi-ng

OpenDMI

Linux FreeBSD NetBSD macOS Windows

OpenDMI reads DMI/SMBIOS data and gives it back as structured data instead of text to parse: a C library, command line tools, machine-readable output and bindings for Go, Python and Rust. Every field has a code, a type and a unit, so the same data reads the same way in the terminal, in JSON and through the API.

The project is under active development, see ROADMAP and CHANGELOG for details.

At a glance

Structures are decoded field by field, including the ones other tools leave as raw bytes:

$ opendmi show -t processor
Processor information
	Socket Designation: U3E1
	Type: Central processor
	Family: Intel Core i5
	Vendor: Intel(R) Corporation
	ID: A4 06 09 00 FF FB EB BF
	Signature:
		Type: 0
		Family: 6
		Model: 154
		Stepping: 4
	Flags: 0xBFEBFBFF
		FPU (floating-point unit on-chip): yes
		VME (virtual mode extension): yes
		...

The same structure in JSON, with stable codes instead of human-readable labels:

$ opendmi export -f json -t processor
{
    "entry": {
        "smbios-version": "3.0"
    },
    "table": [
        {
            "handle": "0x001a",
            "type": 4,
            "length": 185,
            "level": "3.0",
            "state": [
                "decoded",
                "linked"
            ],
            "description": "Processor information",
            "attributes": {
                "socket-designation": "U3E1",
                "type": "central",
                "family": "intel-core-i5",
                "vendor": "Intel(R) Corporation",
                "id": "a4060900fffbebbf",
                "signature": {
                    "type": "0",
                    "family": "6",
                    "model": "154",
                    "stepping": "4"
                },
                "flags": {
                    "fpu": true,
                    "vme": true
                }
            }
        }
    ]
}

The same data from C, with decoded structures mapped to plain C types:

#include <opendmi/context.h>
#include <opendmi/entity/system.h>

dmi_context_t *context = dmi_create(DMI_CONTEXT_FLAG_LINK);

if (dmi_open(context, nullptr)) {
    dmi_registry_t *registry = dmi_get_registry(context);
    dmi_entity_t   *entity   = dmi_registry_lookup_first(registry, DMI_TYPE(SYSTEM), false);
    dmi_system_t   *system   = dmi_entity_info(entity, DMI_TYPE(SYSTEM));

    if (system != nullptr)
        printf("%s %s\n", system->vendor, system->product);
}

dmi_destroy(context);

Why OpenDMI

Features

Components

Component Description Status
libopendmi C/C++ library providing direct interface to DMI/SMBIOS Usable, API not frozen until 1.0
opendmi Command line tool to query DMI/SMBIOS data Usable, import command is on the way
libopendmi-python Python bindings for libopendmi In progress
opendmi-dbus D-Bus service providing access to DMI/SMBIOS data In progress
opendmi-sysfs Linux kernel module providing DMI/SMBIOS data via SysFS Planned
libopendmi-go Go bindings for libopendmi Planned
libopendmi-rust Rust bindings for libopendmi Planned

Everything is scheduled for 1.0, see ROADMAP for the order.

Getting started

Build and install OpenDMI from sources:

$ ./build.sh configure --prefix /usr/local
$ ./build.sh build
$ ./build.sh install

Then read the data of the local system:

$ opendmi show

See Building from sources for configuration options, optional components and packaging.

Usage

The opendmi command line tool provides access to DMI/SMBIOS data. The general usage pattern is:

$ opendmi [global options] <command> [command options]

Global options

Option Description
-v, --version Print version information and exit
-h, --help Print help and exit
-i <path>, --file=<path> Read DMI data from a binary file instead of the system
-d <path>, --device=<path> Set path to memory device (default: /dev/mem)
-m <module>, --module=<module> Enable the specified module
-O, --overlay Apply additional information entries (type 40) to structures
-l, --log Enable logging to the terminal
--log-file=<path> Enable logging to a file
-L <level>, --log-level=<level> Set logging level

Values of options are specified either as a separate argument (-i <path>, --file <path>) or attached to the option (-i<path>, --file=<path>).

Commands

Command Description
show Show SMBIOS structures data
list List SMBIOS structures
entry Show SMBIOS entry point data
types List SMBIOS structure types
explain Explain an SMBIOS structure type
export Export SMBIOS data to external format (JSON, XML, YAML)
dump Dump the entire SMBIOS table to a binary file
import Import SMBIOS data from an external format *
lint Check SMBIOS structures against the rules of the specification
modules List available modules

Use opendmi <command> --help for detailed information on a specific command. Commands marked with an asterisk are on the way.

show

Show SMBIOS structures data in human-readable form. Structures are selected with filter options.

Option Description
-q, --quiet Hide meta-data and handle references
-V, --verbose Show structure versions and states
-D, --dump Show raw structure data instead of decoded fields

list

List SMBIOS structures with their handles and types. Structures are selected with filter options.

Option Description
-r, --raw Raw output (default if standard output is a pipe)

entry

Show SMBIOS entry point data. The command has no options.

types

List SMBIOS structure types. Only standard types are listed by default.

Option Description
-m <module>, --module=<module> List types provided by the specified module
-M, --all-modules List types provided by all modules
-a, --all List all available types
-r, --raw Raw output (default if standard output is a pipe)

explain

Explain an SMBIOS structure type, given by its number or code: opendmi explain [--] <type>. The command has no options.

export

Export SMBIOS data to external format. Structures are selected with filter options.

Option Description
-o <path>, --output=<path> Set output file path (default: standard output)
-f <format>, --format=<format> Set output format: text, json, xml or yaml (default: yaml)
-D, --dump Export raw structure data instead of decoded fields
-p, --pretty Write the values for a person (4 GiB) instead of by their codes (4294967296)
-F, --force Overwrite existing files

dump

Dump the entire SMBIOS table to a binary file, compatible with dmidecode --from-dump.

Option Description
-o <path>, --output=<path> Set output file path (default: smbios.bin)
-F, --force Overwrite existing files

lint

Check SMBIOS data against the rules of the specification.

Option Description
-A, --all-checks Enable the rules which are disabled by default
-e <rule>, --enable=<rule> Check the given rule or group of rules only
-d <rule>, --disable=<rule> Skip the given rule or group of rules
-P, --producer Check the data as if it was produced, not read
-S, --strict Treat warnings as errors
-q, --quiet Report errors only
-R, --list-rules List the rules and exit

Each issue is reported the way a compiler reports a diagnostic, so that the output is readable by the tools that are used to that format:

$ opendmi -i smbios.bin lint
0x0009: warning: firmware@0x0000.rom-size (Platform firmware information): ROM size refers to the extended one, which the structure does not carry [firmware.rom-size]
0x00F3: note: baseboard@0x0002 (Baseboard or module information): string 4 holds whitespace only [string.blank]
0x103C: note: <table>: table has 290 bytes past the end-of-table structure [table.trailing-data]
9 issues: 0 errors, 1 warning, 8 notes

The location is the offset of the issue within the data, followed by the code of the structure and its handle, and by the attribute the issue belongs to. Issues of the entry point and of the table itself are located at <entry> and <table> instead. The rule that has found the issue is named in brackets.

Rules are named <group>.<rule>, e.g. entry.checksum, and -e and -d take either a full name or a group name standing for every rule in it. Naming rules with -e leaves the rest of them out, and a rule named explicitly is checked even if it is disabled by default. Use -R to list the rules along with their severities.

Severity depends on the profile. By default the data is assumed to have been read from a platform, where the defects of the firmware are nothing the reader can fix; -P checks it as data being written, where the same defects are errors.

The command exits with a non-zero status if any issue of the error severity has been found, or any warning in strict mode.

modules

List available modules.

Option Description
-r, --raw Raw output (default if standard output is a pipe)

Filter options

The show, list and export commands show standard and OEM-specific structures by default, excluding inactive and unknown ones. Filter options select structures to show.

Option Description
-H <handle>, --handle=<handle> Only show structures with the given handle(s)
-t <type>, --type=<type> Only show structures of the given type(s), by number or code
-s, --standard Show standard structures
-S, --no-standard Don’t show standard structures
-e, --oem Show OEM-specific structures
-E, --no-oem Don’t show OEM-specific structures
-i, --inactive Show inactive structures
-I, --no-inactive Don’t show inactive structures
-u, --unknown Show unknown structures
-U, --no-unknown Don’t show unknown structures
-m <module>, --module=<module> Show structures provided by the specified enabled module
-M, --all-modules Show structures provided by all enabled modules
-a, --all Show all structures

Output of text commands (e.g. show or types) is shown through the pager set by the PAGER environment variable, or less if it is not set. Unless the LESS environment variable is set, less prints output that fits on one screen directly. Set PAGER to an empty value to disable the pager.

Examples

Show all SMBIOS structures in human-readable format:

$ opendmi show

Show structures of a specific type only:

$ opendmi show -t processor

Show structure versions and decoding states (for example, incomplete for structures, which do not match any specification version):

$ opendmi show -V

Enable the Dell extension module, so that its structures are decoded:

$ opendmi -m dell show

Show structures provided by the enabled module only, hiding the rest:

$ opendmi -m dell show -m dell

List all structures with their handles and types:

$ opendmi list

Show SMBIOS entry point information:

$ opendmi entry

Explain a specific structure type:

$ opendmi explain processor

Export SMBIOS data to YAML (default format):

$ opendmi export -o smbios.yaml

Export SMBIOS data to JSON:

$ opendmi export -f json -o smbios.json

Export to JSON with the values written for a person rather than for a program, so that "memory-type": "ddr4" reads as "memory-type": "DDR4" and a size carries its unit:

$ opendmi export -f json --pretty -o smbios.json

Dump the raw SMBIOS table to a binary file:

$ opendmi dump -o smbios.bin

Read SMBIOS data from a previously saved dump:

$ opendmi -i smbios.bin show

Check a dump against the rules of the specification:

$ opendmi -i smbios.bin lint

Check everything, reporting the peculiarities of the data along with its defects:

$ opendmi lint -A

Check the references between the structures only:

$ opendmi lint -e link -e overlay

Building from sources

Prerequisites

Dependencies

opendmi

libopendmi

Configuring

Use the following command to configure OpenDMI build:

$ ./build.sh configure

This produces a release build by default. Pass --debug to configure a debug build (optimization disabled, debug assertions included):

$ ./build.sh configure --debug

Debug and coverage builds use AddressSanitizer when the runtime of the toolchain runs on the platform, which is checked while configuring, since a runtime the system has outgrown hangs every program before it starts. Pass --without-asan to build without it, or --with-asan to require it and fail to configure instead of falling back.

To set the installation prefix:

$ ./build.sh configure --prefix /usr/local

To enable optional components:

$ ./build.sh configure --enable-dbus --enable-python

To enable all optional components at once:

$ ./build.sh configure --enable-all

To enable optional format support:

$ ./build.sh configure --with-json --with-xml --with-yaml

For all configuration options, see usage:

$ ./build.sh --help

To override defaults persistently without modifying build.conf.dist, create a build.conf file in the project root — settings there take precedence.

Building

Use the following command to build OpenDMI:

$ ./build.sh build

To build using a specific number of parallel jobs:

$ ./build.sh -j 4 build

To use a custom build directory:

$ ./build.sh -b /tmp/opendmi-build build

Testing

OpenDMI uses the CTest framework for testing. You can simply run it to ensure that build was successful:

$ ./build.sh test

To re-run only the failed tests:

$ ./build.sh test --failed

Installing

Use the following command to install OpenDMI to the configured prefix:

$ ./build.sh install

Using the library

The installed library can be found with CMake:

find_package(OpenDMI 0.5 REQUIRED)
target_link_libraries(example PRIVATE OpenDMI::opendmi)

OpenDMI::opendmi and OpenDMI::shared refer to the shared library, and OpenDMI::static refers to the static one. Binary compatibility is not guaranteed between minor versions before 1.0, so the package is only compatible with the same minor version.

The library can also be found with pkg-config:

$ cc example.c $(pkg-config --cflags --libs opendmi)

Packaging

Use the following command to build distributable packages using CPack:

$ ./build.sh package

Cleaning

To remove build artifacts without removing the configuration:

$ ./build.sh clean

To remove the entire build directory including the configuration:

$ ./build.sh distclean

Contributing

The project is open to contributions. Please feel free to test it and create bug reports, feature requests or pull requests on GitHub. You can also help the project by sending SMBIOS dumps to the authors. To get the dump you can use the following command:

$ dmidecode --dump-bin <filename>

Or, using OpenDMI itself:

$ opendmi dump -o <filename>

See CONTRIBUTING for more details. A full list of contributors who helped the project so far can be found in the CONTRIBUTORS.

Licensing

OpenDMI is licensed under BSD 3-clause license. See LICENSE for details. It uses parts of some third-party libraries that are distributed under their own terms (see LICENSE-3RD-PARTY).

SAST Tools

PVS-Studio - static analyzer for C, C++, C#, and Java code.