hostname: add hardware family, sku and version (#36956)

Add support for the hardware family, SKU (Stock-Keeping Unit) and
version. The values are read from the file /etc/machine-info or DMI as
fallback.

The entries are useful to provide an unified interface to collect detail
hardware information. The /etc/machine-info entries enable embedded
devices without UEFI support to provide the information via a common
interface.

Fixes: #31134
This commit is contained in:
Yu Watanabe
2025-05-23 23:17:01 +09:00
committed by GitHub
7 changed files with 186 additions and 9 deletions
+30
View File
@@ -23,6 +23,36 @@ dmi:*:pnTobefilledbyO.E.M.:*
dmi:*:pnToBeFilledByO.E.M.:*
ID_PRODUCT_NAME_IS_RUBBISH=1
dmi:*:pvrDefaultstring:*
dmi:*:pvrDefault string:*
dmi:*:pvrN/A:*
dmi:*:pvrO.E.M.:*
dmi:*:pvrOEM:*
dmi:*:pvrTobefilledbyO.E.M.:*
dmi:*:pvrToBeFilledByO.E.M.:*
dmi:*:pvrTo Be Filled By O.E.M.:*
ID_PRODUCT_VERSION_IS_RUBBISH=1
dmi:*:rvrDefaultstring:*
dmi:*:rvrDefault string:*
dmi:*:rvrN/A:*
dmi:*:rvrO.E.M.:*
dmi:*:rvrOEM:*
dmi:*:rvrTobefilledbyO.E.M.:*
dmi:*:rvrToBeFilledByO.E.M.:*
dmi:*:rvrTo Be Filled By O.E.M.:*
ID_BOARD_VERSION_IS_RUBBISH=1
dmi:*:skuDefaultstring:*
dmi:*:skuDefault string:*
dmi:*:skuN/A:*
dmi:*:skuO.E.M.:*
dmi:*:skuOEM:*
dmi:*:skuTobefilledbyO.E.M.:*
dmi:*:skuToBeFilledByO.E.M.:*
dmi:*:skuTo Be Filled By O.E.M.:*
ID_PRODUCT_SKU_IS_RUBBISH=1
dmi:*:catDefaultstring:*
dmi:*:catDefault string:*
dmi:*:catN/A:*
+18
View File
@@ -154,6 +154,24 @@
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>HARDWARE_SKU=</varname></term>
<listitem><para>Specifies the hardware SKU (Stock-Keeping Unit). If unspecified, the hardware
SKU set in DMI will be used.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>HARDWARE_VERSION=</varname></term>
<listitem><para>Specifies the hardware version. If unspecified, the hardware version set in DMI
will be used.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
+17 -5
View File
@@ -94,6 +94,10 @@ node /org/freedesktop/hostname1 {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s HardwareModel = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s HardwareSKU = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s HardwareVersion = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s FirmwareVersion = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s FirmwareVendor = '...';
@@ -180,6 +184,10 @@ node /org/freedesktop/hostname1 {
<variablelist class="dbus-property" generated="True" extra-ref="HardwareModel"/>
<variablelist class="dbus-property" generated="True" extra-ref="HardwareSKU"/>
<variablelist class="dbus-property" generated="True" extra-ref="HardwareVersion"/>
<variablelist class="dbus-property" generated="True" extra-ref="FirmwareVersion"/>
<variablelist class="dbus-property" generated="True" extra-ref="FirmwareVendor"/>
@@ -306,9 +314,12 @@ node /org/freedesktop/hostname1 {
to the <varname>IMAGE_ID=</varname> and <varname>IMAGE_VERSION=</varname> fields of the
<filename>os-release</filename> file.</para>
<para><varname>HardwareVendor</varname> and <varname>HardwareModel</varname> expose information about the
vendor of the hardware of the system. If no such information can be determined these properties are set
to empty strings.</para>
<para><varname>HardwareVendor</varname>, <varname>HardwareModel</varname>, <varname>HardwareSKU</varname>,
and <varname>HardwareVersion</varname> expose vendor information about the hardware of the system. The
stock keeping unit (SKU) describes a distinct type of hardware for sale, purchase or inventory management.
The SKU and version are only available if they deviate from the model and among each other. Thereby the
version is more specific and only available if it differs from the model and SKU. If no such information
can be determined these properties are set to empty strings.</para>
<para><varname>FirmwareVersion</varname> and <varname>FirmwareVendor</varname> expose information about
the system's firmware, i.e. a version string and a vendor name. If no such information can be determined
@@ -473,8 +484,9 @@ node /org/freedesktop/hostname1 {
<varname>FirmwareDate</varname> were added in version 253.</para>
<para><varname>MachineID</varname>, <varname>BootID</varname> and
<varname>VSockCID</varname> were added in version 256.</para>
<para><varname>ChassisAssetTag</varname>, <varname>OperatingSystemImageID</varname> and
<varname>OperatingSystemImageVersion</varname> were added in version 258.</para>
<para><varname>ChassisAssetTag</varname>, <varname>OperatingSystemImageID</varname>,
<varname>OperatingSystemImageVersion</varname>, <varname>HardwareSKU</varname>, and
<varname>HardwareVersion</varname> were added in version 258.</para>
</refsect2>
</refsect1>
+7
View File
@@ -11,6 +11,13 @@ ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="product_version", ENV{ID_MODEL}="$attr{product_v
ENV{ID_VENDOR}=="", ENV{ID_VENDOR}="$attr{board_vendor}"
ENV{ID_MODEL}=="", ENV{ID_MODEL}="$attr{board_name}"
# stock keeping unit
ENV{ID_PRODUCT_SKU_IS_RUBBISH}!="1", ENV{ID_SKU}="$attr{product_sku}"
# hardware version
ENV{ID_PRODUCT_VERSION_IS_RUBBISH}!="1", ENV{ID_HARDWARE_VERSION}="$attr{product_version}"
ENV{ID_HARDWARE_VERSION}=="", ENV{ID_BOARD_VERSION_IS_RUBBISH}!="1", ENV{ID_HARDWARE_VERSION}="$attr{board_version}"
# chassis asset tag
ENV{MODALIAS}!="", ATTR{chassis_asset_tag}!="", IMPORT{builtin}="hwdb '$attr{modalias}cat$attr{chassis_asset_tag}:'"
ENV{ID_CHASSIS_ASSET_TAG_IS_RUBBISH}!="1", ENV{ID_CHASSIS_ASSET_TAG}="$attr{chassis_asset_tag}"
+20
View File
@@ -67,6 +67,8 @@ typedef struct StatusInfo {
const char *hardware_serial;
sd_id128_t product_uuid;
uint32_t vsock_cid;
const char *hardware_sku;
const char *hardware_version;
} StatusInfo;
static const char* chassis_string_to_glyph(const char *chassis) {
@@ -321,6 +323,22 @@ static int print_status_info(StatusInfo *i) {
return table_log_add_error(r);
}
if (!isempty(i->hardware_sku)) {
r = table_add_many(table,
TABLE_FIELD, "Hardware SKU",
TABLE_STRING, i->hardware_sku);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->hardware_version)) {
r = table_add_many(table,
TABLE_FIELD, "Hardware Version",
TABLE_STRING, i->hardware_version);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->firmware_version)) {
r = table_add_many(table,
TABLE_FIELD, "Firmware Version",
@@ -414,6 +432,8 @@ static int show_all_names(sd_bus *bus) {
{ "HomeURL", "s", NULL, offsetof(StatusInfo, home_url) },
{ "HardwareVendor", "s", NULL, offsetof(StatusInfo, hardware_vendor) },
{ "HardwareModel", "s", NULL, offsetof(StatusInfo, hardware_model) },
{ "HardwareSKU", "s", NULL, offsetof(StatusInfo, hardware_sku) },
{ "HardwareVersion", "s", NULL, offsetof(StatusInfo, hardware_version) },
{ "FirmwareVersion", "s", NULL, offsetof(StatusInfo, firmware_version) },
{ "FirmwareDate", "t", NULL, offsetof(StatusInfo, firmware_date) },
{ "MachineID", "ay", bus_map_id128, offsetof(StatusInfo, machine_id) },
+92 -4
View File
@@ -66,6 +66,8 @@ typedef enum {
PROP_LOCATION,
PROP_HARDWARE_VENDOR,
PROP_HARDWARE_MODEL,
PROP_HARDWARE_SKU,
PROP_HARDWARE_VERSION,
/* Read from /etc/os-release (or /usr/lib/os-release) */
PROP_OS_PRETTY_NAME,
@@ -170,7 +172,9 @@ static void context_read_machine_info(Context *c) {
(UINT64_C(1) << PROP_DEPLOYMENT) |
(UINT64_C(1) << PROP_LOCATION) |
(UINT64_C(1) << PROP_HARDWARE_VENDOR) |
(UINT64_C(1) << PROP_HARDWARE_MODEL));
(UINT64_C(1) << PROP_HARDWARE_MODEL) |
(UINT64_C(1) << PROP_HARDWARE_SKU) |
(UINT64_C(1) << PROP_HARDWARE_VERSION));
r = parse_env_file(NULL, "/etc/machine-info",
"PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
@@ -179,7 +183,9 @@ static void context_read_machine_info(Context *c) {
"DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
"LOCATION", &c->data[PROP_LOCATION],
"HARDWARE_VENDOR", &c->data[PROP_HARDWARE_VENDOR],
"HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL]);
"HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL],
"HARDWARE_SKU", &c->data[PROP_HARDWARE_SKU],
"HARDWARE_VERSION", &c->data[PROP_HARDWARE_VERSION]);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
@@ -356,6 +362,55 @@ static int get_hardware_model(Context *c, char **ret) {
return get_dmi_properties(c, STRV_MAKE_CONST("ID_MODEL_FROM_DATABASE", "ID_MODEL"), ret);
}
static int get_hardware_sku(Context *c, char **ret) {
_cleanup_free_ char *model = NULL, *sku = NULL;
int r;
r = get_dmi_property(c, "ID_SKU", &sku);
if (r < 0)
return r;
/* Suppress reporting the SKU field, if it's the same string as the
* model field, which it appears to be on various systems */
r = get_hardware_model(c, &model);
if (r < 0) {
if (r != -ENOENT)
return r;
} else if (streq_ptr(sku, model))
return -ENOENT;
*ret = TAKE_PTR(sku);
return 0;
}
static int get_hardware_version(Context *c, char **ret) {
_cleanup_free_ char *version = NULL;
int r;
r = get_dmi_property(c, "ID_HARDWARE_VERSION", &version);
if (r < 0)
return r;
/* Suppress reporting the version field, if it's the same string as the
* model or sku field, which it appears to be on various systems */
for (int i = 0; i < 2; i++) {
_cleanup_free_ char *value = NULL;
if (i == 0)
r = get_hardware_model(c, &value);
else
r = get_hardware_sku(c, &value);
if (r < 0) {
if (r != -ENOENT)
return r;
} else if (streq_ptr(version, value))
return -ENOENT;
}
*ret = TAKE_PTR(version);
return 0;
}
static int get_sysattr(sd_device *device, const char *key, char **ret) {
const char *s;
int r;
@@ -824,7 +879,8 @@ static int property_get_hardware_property(
assert(reply);
assert(c);
assert(IN_SET(prop, PROP_HARDWARE_VENDOR, PROP_HARDWARE_MODEL));
assert(IN_SET(prop, PROP_HARDWARE_VENDOR, PROP_HARDWARE_MODEL,
PROP_HARDWARE_SKU, PROP_HARDWARE_VERSION));
assert(getter);
context_read_machine_info(c);
@@ -859,6 +915,30 @@ static int property_get_hardware_model(
return property_get_hardware_property(reply, userdata, PROP_HARDWARE_MODEL, get_hardware_model);
}
static int property_get_hardware_sku(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return property_get_hardware_property(reply, userdata, PROP_HARDWARE_SKU, get_hardware_sku);
}
static int property_get_hardware_version(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return property_get_hardware_property(reply, userdata, PROP_HARDWARE_VERSION, get_hardware_version);
}
static int property_get_firmware_version(
sd_bus *bus,
const char *path,
@@ -1539,7 +1619,7 @@ static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_
static int build_describe_response(Context *c, bool privileged, sd_json_variant **ret) {
_cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL,
*chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
*firmware_vendor = NULL, *chassis_asset_tag = NULL;
*firmware_vendor = NULL, *chassis_asset_tag = NULL, *sku = NULL, *hardware_version = NULL;
_cleanup_strv_free_ char **os_release_pairs = NULL, **machine_info_pairs = NULL;
usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
@@ -1575,6 +1655,10 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant
(void) get_hardware_vendor(c, &vendor);
if (isempty(c->data[PROP_HARDWARE_MODEL]))
(void) get_hardware_model(c, &model);
if (isempty(c->data[PROP_HARDWARE_SKU]))
(void) get_hardware_sku(c, &sku);
if (isempty(c->data[PROP_HARDWARE_VERSION]))
(void) get_hardware_version(c, &hardware_version);
if (privileged) {
/* The product UUID and hardware serial is only available to privileged clients */
@@ -1628,6 +1712,8 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant
SD_JSON_BUILD_PAIR_STRING("HardwareVendor", vendor ?: c->data[PROP_HARDWARE_VENDOR]),
SD_JSON_BUILD_PAIR_STRING("HardwareModel", model ?: c->data[PROP_HARDWARE_MODEL]),
SD_JSON_BUILD_PAIR_STRING("HardwareSerial", serial),
SD_JSON_BUILD_PAIR_STRING("HardwareSKU", sku ?: c->data[PROP_HARDWARE_SKU]),
SD_JSON_BUILD_PAIR_STRING("HardwareVersion", hardware_version ?: c->data[PROP_HARDWARE_VERSION]),
SD_JSON_BUILD_PAIR_STRING("FirmwareVersion", firmware_version),
SD_JSON_BUILD_PAIR_STRING("FirmwareVendor", firmware_vendor),
JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
@@ -1699,6 +1785,8 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("OperatingSystemImageVersion", "s", property_get_os_release_field, offsetof(Context, data[PROP_OS_IMAGE_VERSION]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HardwareSKU", "s", property_get_hardware_sku, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HardwareVersion", "s", property_get_hardware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareVersion", "s", property_get_firmware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareVendor", "s", property_get_firmware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FirmwareDate", "t", property_get_firmware_date, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+2
View File
@@ -27,6 +27,8 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_OUTPUT(HardwareVendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(HardwareModel, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(HardwareSerial, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(HardwareSKU, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(HardwareVersion, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(FirmwareVersion, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(FirmwareVendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(FirmwareDate, SD_VARLINK_INT, SD_VARLINK_NULLABLE),