Expose chassis asset tag in hostnamed (#36487)

Closes #36442
This commit is contained in:
Mike Yuan
2025-02-26 14:28:26 +01:00
committed by GitHub
7 changed files with 115 additions and 31 deletions

View File

@@ -23,6 +23,16 @@ dmi:*:pnTobefilledbyO.E.M.:*
dmi:*:pnToBeFilledByO.E.M.:*
ID_PRODUCT_NAME_IS_RUBBISH=1
dmi:*:catDefaultstring:*
dmi:*:catDefault string:*
dmi:*:catN/A:*
dmi:*:catO.E.M.:*
dmi:*:catOEM:*
dmi:*:catTobefilledbyO.E.M.:*
dmi:*:catToBeFilledByO.E.M.:*
dmi:*:catTo Be Filled By O.E.M.:*
ID_CHASSIS_ASSET_TAG_IS_RUBBISH=1
# Fix "Lenovo" capitalization in /sys/class/dmi/id/sys_vendor
dmi:bvnLENOVO*
ID_SYSFS_ATTRIBUTE_MODEL=product_version

View File

@@ -101,6 +101,8 @@ node /org/freedesktop/hostname1 {
readonly ay BootID = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u VSockCID = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ChassisAssetTag = '...';
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
@@ -182,6 +184,8 @@ node /org/freedesktop/hostname1 {
<variablelist class="dbus-property" generated="True" extra-ref="VSockCID"/>
<variablelist class="dbus-property" generated="True" extra-ref="ChassisAssetTag"/>
<!--End of Autogenerated section-->
<para>Whenever the hostname or other metadata is changed via the daemon,
@@ -301,6 +305,9 @@ node /org/freedesktop/hostname1 {
an unsigned 64bit value, in µs since the UNIX epoch, UTC. If not known
<constant>UNIT64_MAX</constant>.</para>
<para><varname>ChassisAssetTag</varname> exposes an unique identifier of the system chassis. If this
information is not known this property is set to an empty string.</para>
<refsect2>
<title>Methods</title>
@@ -453,6 +460,7 @@ 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> was added in version 258.</para>
</refsect2>
</refsect1>

View File

@@ -11,4 +11,8 @@ 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}"
# 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}"
LABEL="dmi_end"

View File

@@ -44,6 +44,7 @@ typedef struct StatusInfo {
const char *pretty_hostname;
const char *icon_name;
const char *chassis;
const char *chassis_asset_tag;
const char *deployment;
const char *location;
const char *kernel_name;
@@ -164,6 +165,14 @@ static int print_status_info(StatusInfo *i) {
return table_log_add_error(r);
}
if (!isempty(i->chassis_asset_tag)) {
r = table_add_many(table,
TABLE_FIELD, "Chassis Asset Tag",
TABLE_STRING, i->chassis_asset_tag);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->deployment)) {
r = table_add_many(table,
TABLE_FIELD, "Deployment",
@@ -373,6 +382,7 @@ static int show_all_names(sd_bus *bus) {
{ "PrettyHostname", "s", NULL, offsetof(StatusInfo, pretty_hostname) },
{ "IconName", "s", NULL, offsetof(StatusInfo, icon_name) },
{ "Chassis", "s", NULL, offsetof(StatusInfo, chassis) },
{ "ChassisAssetTag", "s", NULL, offsetof(StatusInfo, chassis_asset_tag)},
{ "Deployment", "s", NULL, offsetof(StatusInfo, deployment) },
{ "Location", "s", NULL, offsetof(StatusInfo, location) },
{ "KernelName", "s", NULL, offsetof(StatusInfo, kernel_name) },

View File

@@ -320,6 +320,10 @@ static int get_dmi_properties(Context *c, const char * const * keys, char **ret)
return r;
}
static int get_chassis_asset_tag(Context *c, char **ret) {
return get_dmi_property(c, "ID_CHASSIS_ASSET_TAG", ret);
}
static int get_hardware_vendor(Context *c, char **ret) {
return get_dmi_properties(c, STRV_MAKE_CONST("ID_VENDOR_FROM_DATABASE", "ID_VENDOR"), ret);
}
@@ -881,6 +885,24 @@ static int property_get_firmware_date(
return sd_bus_message_append(reply, "t", firmware_date);
}
static int property_get_chassis_asset_tag(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
_cleanup_free_ char *chassis_asset_tag = NULL;
Context *c = ASSERT_PTR(userdata);
(void) get_chassis_asset_tag(c, &chassis_asset_tag);
return sd_bus_message_append(reply, "s", chassis_asset_tag);
}
static int property_get_hostname(
sd_bus *bus,
const char *path,
@@ -1461,7 +1483,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;
*firmware_vendor = NULL, *chassis_asset_tag = 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;
@@ -1512,6 +1534,7 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant
(void) get_firmware_version(c, &firmware_version);
(void) get_firmware_vendor(c, &firmware_vendor);
(void) get_firmware_date(c, &firmware_date);
(void) get_chassis_asset_tag(c, &chassis_asset_tag);
if (c->data[PROP_OS_SUPPORT_END])
(void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
@@ -1531,29 +1554,30 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant
r = sd_json_buildo(
&v,
SD_JSON_BUILD_PAIR("Hostname", SD_JSON_BUILD_STRING(hn)),
SD_JSON_BUILD_PAIR("StaticHostname", SD_JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])),
SD_JSON_BUILD_PAIR("PrettyHostname", SD_JSON_BUILD_STRING(c->data[PROP_PRETTY_HOSTNAME])),
SD_JSON_BUILD_PAIR("DefaultHostname", SD_JSON_BUILD_STRING(dhn)),
SD_JSON_BUILD_PAIR("HostnameSource", SD_JSON_BUILD_STRING(hostname_source_to_string(c->hostname_source))),
SD_JSON_BUILD_PAIR("IconName", SD_JSON_BUILD_STRING(in ?: c->data[PROP_ICON_NAME])),
SD_JSON_BUILD_PAIR("Chassis", SD_JSON_BUILD_STRING(chassis)),
SD_JSON_BUILD_PAIR("Deployment", SD_JSON_BUILD_STRING(c->data[PROP_DEPLOYMENT])),
SD_JSON_BUILD_PAIR("Location", SD_JSON_BUILD_STRING(c->data[PROP_LOCATION])),
SD_JSON_BUILD_PAIR("KernelName", SD_JSON_BUILD_STRING(u.sysname)),
SD_JSON_BUILD_PAIR("KernelRelease", SD_JSON_BUILD_STRING(u.release)),
SD_JSON_BUILD_PAIR("KernelVersion", SD_JSON_BUILD_STRING(u.version)),
SD_JSON_BUILD_PAIR("OperatingSystemPrettyName", SD_JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])),
SD_JSON_BUILD_PAIR("OperatingSystemCPEName", SD_JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])),
SD_JSON_BUILD_PAIR("OperatingSystemHomeURL", SD_JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])),
SD_JSON_BUILD_PAIR_STRING("Hostname", hn),
SD_JSON_BUILD_PAIR_STRING("StaticHostname", c->data[PROP_STATIC_HOSTNAME]),
SD_JSON_BUILD_PAIR_STRING("PrettyHostname", c->data[PROP_PRETTY_HOSTNAME]),
SD_JSON_BUILD_PAIR_STRING("DefaultHostname", dhn),
SD_JSON_BUILD_PAIR_STRING("HostnameSource", hostname_source_to_string(c->hostname_source)),
SD_JSON_BUILD_PAIR_STRING("IconName", in ?: c->data[PROP_ICON_NAME]),
SD_JSON_BUILD_PAIR_STRING("Chassis", chassis),
SD_JSON_BUILD_PAIR_STRING("ChassisAssetTag", chassis_asset_tag),
SD_JSON_BUILD_PAIR_STRING("Deployment", c->data[PROP_DEPLOYMENT]),
SD_JSON_BUILD_PAIR_STRING("Location", c->data[PROP_LOCATION]),
SD_JSON_BUILD_PAIR_STRING("KernelName", u.sysname),
SD_JSON_BUILD_PAIR_STRING("KernelRelease", u.release),
SD_JSON_BUILD_PAIR_STRING("KernelVersion", u.version),
SD_JSON_BUILD_PAIR_STRING("OperatingSystemPrettyName", c->data[PROP_OS_PRETTY_NAME]),
SD_JSON_BUILD_PAIR_STRING("OperatingSystemCPEName", c->data[PROP_OS_CPE_NAME]),
SD_JSON_BUILD_PAIR_STRING("OperatingSystemHomeURL", c->data[PROP_OS_HOME_URL]),
JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol),
SD_JSON_BUILD_PAIR("OperatingSystemReleaseData", JSON_BUILD_STRV_ENV_PAIR(os_release_pairs)),
SD_JSON_BUILD_PAIR("MachineInformationData", JSON_BUILD_STRV_ENV_PAIR(machine_info_pairs)),
SD_JSON_BUILD_PAIR("HardwareVendor", SD_JSON_BUILD_STRING(vendor ?: c->data[PROP_HARDWARE_VENDOR])),
SD_JSON_BUILD_PAIR("HardwareModel", SD_JSON_BUILD_STRING(model ?: c->data[PROP_HARDWARE_MODEL])),
SD_JSON_BUILD_PAIR("HardwareSerial", SD_JSON_BUILD_STRING(serial)),
SD_JSON_BUILD_PAIR("FirmwareVersion", SD_JSON_BUILD_STRING(firmware_version)),
SD_JSON_BUILD_PAIR("FirmwareVendor", SD_JSON_BUILD_STRING(firmware_vendor)),
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("FirmwareVersion", firmware_version),
SD_JSON_BUILD_PAIR_STRING("FirmwareVendor", firmware_vendor),
JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
SD_JSON_BUILD_PAIR_ID128("MachineID", machine_id),
SD_JSON_BUILD_PAIR_ID128("BootID", boot_id),
@@ -1627,6 +1651,7 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("MachineID", "ay", property_get_machine_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("VSockCID", "u", property_get_vsock_cid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ChassisAssetTag", "s", property_get_chassis_asset_tag, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD_WITH_ARGS("SetHostname",
SD_BUS_ARGS("s", hostname, "b", interactive),

View File

@@ -33,7 +33,9 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_OUTPUT(MachineID, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_OUTPUT(BootID, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_OUTPUT(ProductUUID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_OUTPUT(VSockCID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_OUTPUT(VSockCID, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("An unique identifier of the system chassis."),
SD_VARLINK_DEFINE_OUTPUT(ChassisAssetTag, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Hostname,

View File

@@ -104,15 +104,7 @@ restore_sysfs_dmi() {
stop_hostnamed
}
testcase_firmware_date() {
# No DMI on s390x or ppc
if [[ ! -d /sys/class/dmi/id ]]; then
echo "/sys/class/dmi/id not found, skipping firmware date tests."
return 0
fi
trap restore_sysfs_dmi RETURN
fake_sysfs_dmi() {
# Ignore /sys being mounted as tmpfs
mkdir -p /run/systemd/system/systemd-hostnamed.service.d/
cat >/run/systemd/system/systemd-hostnamed.service.d/override.conf <<EOF
@@ -124,6 +116,18 @@ EOF
mount -t tmpfs none /sys/class/dmi/id
echo '1' >/sys/class/dmi/id/uevent
}
testcase_firmware_date() {
# No DMI on s390x or ppc
if [[ ! -d /sys/class/dmi/id ]]; then
echo "/sys/class/dmi/id not found, skipping firmware date tests."
return 0
fi
trap restore_sysfs_dmi RETURN
fake_sysfs_dmi
echo '09/08/2000' >/sys/class/dmi/id/bios_date
stop_hostnamed
@@ -138,6 +142,27 @@ EOF
assert_not_in 'Firmware Date' "$(hostnamectl)"
}
testcase_hardware_serial() {
# No DMI on s390x or ppc
if [[ ! -d /sys/class/dmi/id ]]; then
echo "/sys/class/dmi/id not found, skipping firmware date tests."
return 0
fi
trap restore_sysfs_dmi RETURN
fake_sysfs_dmi
echo '1234' >/sys/class/dmi/id/board_serial
stop_hostnamed
assert_eq "$(hostnamectl --json=short | jq --raw-output .HardwareSerial)" "1234"
# product_serial is preferred over board_serial
echo '4321' >/sys/class/dmi/id/product_serial
stop_hostnamed
assert_eq "$(hostnamectl --json=short | jq --raw-output .HardwareSerial)" "4321"
}
testcase_nss-myhostname() {
local database host i