hostnamed: allow marking serial number as rubbish

Some systems, Supermicro in particular, place the serial number on the
Baseboard (DMI type 2) rather than System Information (DMI type 1).

Two new flags for hwdb are added:
* ID_PRODUCT_SERIAL_IS_RUBBISH
* ID_BOARD_SERIAL_IS_RUBBISH

Tested on:
* Supermicro X10DRW-iT
* Supermicro X11SPW-CTF

Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
This commit is contained in:
Pat Riehecky authored and Yu Watanabe committed 2026-11-04 08:40:16 +09:00
1 parent 07dbaa6ab0
commit f698e5a70f
5 files changed
+43 -5

No files matched your search

+1
View File
@@ -90,3 +90,4 @@ dmi:*:svnSupermicro:pnSuper Server:*
dmi:*:svnSupermicro:pnSuperServer:*
ID_PRODUCT_NAME_IS_RUBBISH=1
ID_PRODUCT_VERSION_IS_RUBBISH=1
ID_PRODUCT_SERIAL_IS_RUBBISH=1
+2
View File
@@ -263,6 +263,8 @@ def property_grammar():
('ID_PRODUCT_NAME_IS_RUBBISH', zero_one),
('ID_PRODUCT_VERSION_IS_RUBBISH', zero_one),
('ID_BOARD_VERSION_IS_RUBBISH', zero_one),
('ID_PRODUCT_SERIAL_IS_RUBBISH', zero_one),
('ID_BOARD_SERIAL_IS_RUBBISH', zero_one),
('ID_PRODUCT_SKU_IS_RUBBISH', zero_one),
('ID_CHASSIS_ASSET_TAG_IS_RUBBISH', zero_one),
('ID_CHASSIS', name_literal),
+8
View File
@@ -19,6 +19,14 @@ ENV{ID_PRODUCT_SKU_IS_RUBBISH}!="1", ENV{ID_SKU}="$attr{product_sku}"
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}"
# Hardware serial number. The system serial (DMI type 1) is preferred; fall back to the baseboard
# serial (DMI type 2) when the system serial is missing or flagged as rubbish. This mirrors how
# ID_MODEL and ID_HARDWARE_VERSION are selected above. The serial value itself is not copied into
# the udev database, because DMI serials are root-readable (0400) in sysfs; instead, only the
# selected attribute name is exported so hostnamed can read the raw value as root.
ENV{ID_PRODUCT_SERIAL_IS_RUBBISH}!="1", ATTR{product_serial}!="", ENV{ID_SYSFS_ATTRIBUTE_SERIAL}="product_serial"
ENV{ID_SYSFS_ATTRIBUTE_SERIAL}=="", ENV{ID_BOARD_SERIAL_IS_RUBBISH}!="1", ATTR{board_serial}!="", ENV{ID_SYSFS_ATTRIBUTE_SERIAL}="board_serial"
# 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}"
+12 -5
View File
@@ -460,16 +460,23 @@ static int get_device_tree_sysattr(Context *c, const char *key, char **ret) {
}
static int get_hardware_serial(Context *c, char **ret) {
_cleanup_free_ char *attr = NULL;
int r;
assert(c);
assert(ret);
FOREACH_STRING(attr, "product_serial", "board_serial") {
r = get_dmi_sysattr(c, attr, ret);
if (r >= 0 || !ERRNO_IS_NEG_DEVICE_ABSENT(r))
return r;
}
/* 60-dmi-id.rules selects which DMI serial attribute to report: the product serial number
* (DMI type 1) is preferred, unless hwdb flags it as rubbish, in which case the baseboard
* serial number (DMI type 2) is used instead. If both are rubbish (or the system lacks
* DMI), fall through to the device tree serial number. The serial value is read directly
* from sysfs as root, rather than copied into the udev database, to avoid exposing it to
* unprivileged users. */
r = get_dmi_property(c, "ID_SYSFS_ATTRIBUTE_SERIAL", &attr);
if (r >= 0)
return get_dmi_sysattr(c, attr, ret);
if (!ERRNO_IS_NEG_DEVICE_ABSENT(r))
return r;
return get_device_tree_sysattr(c, "serial-number", ret);
}
+20
View File
@@ -154,13 +154,33 @@ testcase_hardware_serial() {
fake_sysfs_dmi
echo '1234' >/sys/class/dmi/id/board_serial
# 60-dmi-id.rules sets ID_SYSFS_ATTRIBUTE_SERIAL to the baseboard serial attribute when the
# product serial is missing; sd_device picks up unknown keys from the uevent file as device
# properties, so write ID_SYSFS_ATTRIBUTE_SERIAL the same way the rules file would.
# Use a subsystem with no db (hostnamed-test) to avoid sd_device loading /run/udev/data.
printf 'SUBSYSTEM=hostnamed-test\nID_SYSFS_ATTRIBUTE_SERIAL=board_serial\n' >>/sys/class/dmi/id/uevent
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
printf 'SUBSYSTEM=hostnamed-test\nID_SYSFS_ATTRIBUTE_SERIAL=product_serial\n' > /sys/class/dmi/id/uevent
stop_hostnamed
assert_eq "$(hostnamectl --json=short | jq --raw-output .HardwareSerial)" "4321"
# hwdb can flag DMI type 1 product_serial as rubbish; 60-dmi-id.rules then sets
# ID_SYSFS_ATTRIBUTE_SERIAL to the DMI type 2 baseboard serial attribute instead, and hostnamed
# reports it even though the (rubbish) product_serial is still readable via sysfs.
printf 'SUBSYSTEM=hostnamed-test\nID_SYSFS_ATTRIBUTE_SERIAL=board_serial\n' > /sys/class/dmi/id/uevent
stop_hostnamed
assert_eq "$(hostnamectl --json=short | jq --raw-output .HardwareSerial)" "1234"
# When both DMI serials are rubbish, the rules leave ID_SYSFS_ATTRIBUTE_SERIAL unset; hostnamed
# must not read the sysfs attributes directly but fall through to the device tree serial, which
# is absent here.
printf 'SUBSYSTEM=hostnamed-test\n' > /sys/class/dmi/id/uevent
stop_hostnamed
assert_eq "$(hostnamectl --json=short | jq --raw-output .HardwareSerial)" "null"
}
testcase_nss-myhostname() {