From 39936a1b89599e7d1b32c6e749113d0ab7e63661 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Wed, 12 Feb 2025 21:39:59 +0100 Subject: [PATCH 1/3] test: assert that product_serial is preferred over board_serial --- test/units/TEST-71-HOSTNAME.sh | 43 +++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/test/units/TEST-71-HOSTNAME.sh b/test/units/TEST-71-HOSTNAME.sh index dc3f587ea3..0813a07d46 100755 --- a/test/units/TEST-71-HOSTNAME.sh +++ b/test/units/TEST-71-HOSTNAME.sh @@ -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 </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 From 7e638ccf59a15fc4d15cbc95fd216d48be9205e3 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Wed, 12 Feb 2025 21:13:04 +0100 Subject: [PATCH 2/3] hostnamed: expose ChassisAssetTag in dbus/varlink Expose /sys/class/dmi/id/chassis_asset_tag in varlink/dbus commonly used by companies to track inventory such as laptops. On desktops and other products the `chassis_asset_tag` can contain rubbish similar to product_name/product_vendor. Closes: #36442 --- hwdb.d/20-dmi-id.hwdb | 10 +++++++++ man/org.freedesktop.hostname1.xml | 8 +++++++ rules.d/60-dmi-id.rules | 4 ++++ src/hostname/hostnamectl.c | 10 +++++++++ src/hostname/hostnamed.c | 27 +++++++++++++++++++++++- src/shared/varlink-io.systemd.Hostname.c | 4 +++- 6 files changed, 61 insertions(+), 2 deletions(-) diff --git a/hwdb.d/20-dmi-id.hwdb b/hwdb.d/20-dmi-id.hwdb index 905d6923bb..e324d89c5b 100644 --- a/hwdb.d/20-dmi-id.hwdb +++ b/hwdb.d/20-dmi-id.hwdb @@ -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 diff --git a/man/org.freedesktop.hostname1.xml b/man/org.freedesktop.hostname1.xml index e6eac25180..ee34bf441c 100644 --- a/man/org.freedesktop.hostname1.xml +++ b/man/org.freedesktop.hostname1.xml @@ -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 { + + 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 UNIT64_MAX. + ChassisAssetTag exposes an unique identifier of the system chassis. If this + information is not known this property is set to an empty string. + Methods @@ -453,6 +460,7 @@ node /org/freedesktop/hostname1 { FirmwareDate were added in version 253. MachineID, BootID and VSockCID were added in version 256. + ChassisAssetTag was added in version 258. diff --git a/rules.d/60-dmi-id.rules b/rules.d/60-dmi-id.rules index 6c61ea24ab..b112bd7880 100644 --- a/rules.d/60-dmi-id.rules +++ b/rules.d/60-dmi-id.rules @@ -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" diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 2d1334f654..c57d821fce 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -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) }, diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a4549da826..1dd4faa7f0 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -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); @@ -1538,6 +1561,7 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant 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_STRING("ChassisAssetTag", chassis_asset_tag), 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)), @@ -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), diff --git a/src/shared/varlink-io.systemd.Hostname.c b/src/shared/varlink-io.systemd.Hostname.c index c9aadd28e9..1430d86beb 100644 --- a/src/shared/varlink-io.systemd.Hostname.c +++ b/src/shared/varlink-io.systemd.Hostname.c @@ -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, From d0f6d705484644294a84a7badf05fb386e02e2db Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 23 Feb 2025 16:59:30 +0100 Subject: [PATCH 3/3] hostnamed: prefer using SD_JSON_BUILD_PAIR_STRING --- src/hostname/hostnamed.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 1dd4faa7f0..6f242776a0 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -1554,30 +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_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("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("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),