From 8c8b1800e90d4307397300ef32b0f6d95efad057 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 22 Jan 2022 23:53:09 +0900 Subject: [PATCH 1/4] hostname: introduce context_get_chassis() and use it everywhere Follow-up for 4b35eb2579b226785f0d94129a7652450f9723fd. --- src/hostname/hostnamed.c | 113 +++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 559326b9f5..3e2fa94c61 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -166,6 +166,41 @@ static void context_read_os_release(Context *c) { c->etc_os_release_stat = current_stat; } +static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + _cleanup_free_ char *b = NULL; + const char *s = NULL; + int r; + + r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id"); + if (r < 0) + return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m"); + + if (database_key) + (void) sd_device_get_property_value(device, database_key, &s); + if (!s && regular_key) + (void) sd_device_get_property_value(device, regular_key, &s); + + if (s) { + b = strdup(s); + if (!b) + return -ENOMEM; + } + + if (ret) + *ret = TAKE_PTR(b); + + return !!s; +} + +static int get_hardware_vendor(char **ret) { + return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret); +} + +static int get_hardware_model(char **ret) { + return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret); +} + static const char* valid_chassis(const char *chassis) { assert(chassis); @@ -318,15 +353,31 @@ try_devicetree: return chassis; } -static char* context_fallback_icon_name(Context *c) { - const char *chassis; +static char* context_get_chassis(Context *c) { + const char *fallback; + char *dmi; assert(c); if (!isempty(c->data[PROP_CHASSIS])) - return strjoin("computer-", c->data[PROP_CHASSIS]); + return strdup(c->data[PROP_CHASSIS]); - chassis = fallback_chassis(); + if (get_dmi_data("ID_CHASSIS", NULL, &dmi) >= 0) + return dmi; + + fallback = fallback_chassis(); + if (fallback) + return strdup(fallback); + + return NULL; +} + +static char* context_fallback_icon_name(Context *c) { + _cleanup_free_ char *chassis = NULL; + + assert(c); + + chassis = context_get_chassis(c); if (chassis) return strjoin("computer-", chassis); @@ -464,41 +515,6 @@ static int context_write_data_machine_info(Context *c) { return 0; } -static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) { - _cleanup_(sd_device_unrefp) sd_device *device = NULL; - _cleanup_free_ char *b = NULL; - const char *s = NULL; - int r; - - r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id"); - if (r < 0) - return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m"); - - if (database_key) - (void) sd_device_get_property_value(device, database_key, &s); - if (!s && regular_key) - (void) sd_device_get_property_value(device, regular_key, &s); - - if (s) { - b = strdup(s); - if (!b) - return -ENOMEM; - } - - if (ret) - *ret = TAKE_PTR(b); - - return !!s; -} - -static int get_hardware_vendor(char **ret) { - return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret); -} - -static int get_hardware_model(char **ret) { - return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret); -} - static int property_get_hardware_vendor( sd_bus *bus, const char *path, @@ -724,19 +740,14 @@ static int property_get_chassis( void *userdata, sd_bus_error *error) { + _cleanup_free_ char *chassis = NULL; Context *c = userdata; - _cleanup_free_ char *dmi_chassis = NULL; - const char *name = NULL; context_read_machine_info(c); - if (isempty(c->data[PROP_CHASSIS])) { - if (get_dmi_data("ID_CHASSIS", NULL, &dmi_chassis) <= 0) - name = fallback_chassis(); - } else - name = c->data[PROP_CHASSIS]; + chassis = context_get_chassis(c); - return sd_bus_message_append(reply, "s", name ?: dmi_chassis); + return sd_bus_message_append(reply, "s", chassis); } static int property_get_uname_field( @@ -1022,11 +1033,10 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err } static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) { - _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL, *vendor = NULL, *model = NULL; + _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL, *chassis = NULL, *vendor = NULL, *model = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; sd_id128_t product_uuid = SD_ID128_NULL; - const char *chassis = NULL; Context *c = userdata; bool privileged; struct utsname u; @@ -1073,8 +1083,7 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro if (isempty(c->data[PROP_ICON_NAME])) in = context_fallback_icon_name(c); - if (isempty(c->data[PROP_CHASSIS])) - chassis = fallback_chassis(); + chassis = context_get_chassis(c); assert_se(uname(&u) >= 0); @@ -1091,7 +1100,7 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro JSON_BUILD_PAIR("DefaultHostname", JSON_BUILD_STRING(dhn)), JSON_BUILD_PAIR("HostnameSource", JSON_BUILD_STRING(hostname_source_to_string(c->hostname_source))), JSON_BUILD_PAIR("IconName", JSON_BUILD_STRING(in ?: c->data[PROP_ICON_NAME])), - JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis ?: c->data[PROP_CHASSIS])), + JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis)), JSON_BUILD_PAIR("Deployment", JSON_BUILD_STRING(c->data[PROP_DEPLOYMENT])), JSON_BUILD_PAIR("Location", JSON_BUILD_STRING(c->data[PROP_LOCATION])), JSON_BUILD_PAIR("KernelName", JSON_BUILD_STRING(u.sysname)), From 4fc7e4f374bf4401330e90e267227267abf1dcac Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 22 Jan 2022 10:44:50 +0900 Subject: [PATCH 2/4] hostname: allow to override hardware vendor and model Sometimes hardware vendor does not set DMI info correctly. Already there is a way that the dbus properties can be overriden by using hwdb. But that is not user friendly. This adds two new fields in /etc/machine-info. Closes #22207. --- man/machine-info.xml | 14 +++++++++++ src/hostname/hostnamed.c | 51 ++++++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/man/machine-info.xml b/man/machine-info.xml index 0f57cbdb88..4467c59c94 100644 --- a/man/machine-info.xml +++ b/man/machine-info.xml @@ -139,6 +139,20 @@ machine-id5 will be used. + + + VENDOR= + + Specifies the hardware vendor. If unspecified, the hardware vendor set in DMI + or hwdb will be used. + + + + MODEL= + + Specifies the hardware model. If unspecified, the hardware model set in DMI or + hwdb will be used. + diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 3e2fa94c61..8a9a180d63 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -43,7 +43,7 @@ /* Properties we cache are indexed by an enum, to make invalidation easy and systematic (as we can iterate * through them all, and they are uniformly strings). */ -enum { +typedef enum { /* Read from /etc/hostname */ PROP_STATIC_HOSTNAME, @@ -53,6 +53,8 @@ enum { PROP_CHASSIS, PROP_DEPLOYMENT, PROP_LOCATION, + PROP_VENDOR, + PROP_MODEL, /* Read from /etc/os-release (or /usr/lib/os-release) */ PROP_OS_PRETTY_NAME, @@ -60,7 +62,7 @@ enum { PROP_OS_HOME_URL, _PROP_MAX, _PROP_INVALID = -EINVAL, -}; +} HostProperty; typedef struct Context { char *data[_PROP_MAX]; @@ -133,7 +135,9 @@ static void context_read_machine_info(Context *c) { "ICON_NAME", &c->data[PROP_ICON_NAME], "CHASSIS", &c->data[PROP_CHASSIS], "DEPLOYMENT", &c->data[PROP_DEPLOYMENT], - "LOCATION", &c->data[PROP_LOCATION]); + "LOCATION", &c->data[PROP_LOCATION], + "VENDOR", &c->data[PROP_VENDOR], + "MODEL", &c->data[PROP_MODEL]); if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m"); @@ -515,6 +519,27 @@ static int context_write_data_machine_info(Context *c) { return 0; } +static int property_get_hardware_property( + sd_bus_message *reply, + Context *c, + HostProperty prop, + int (*getter)(char **)) { + + _cleanup_free_ char *from_dmi = NULL; + + assert(reply); + assert(c); + assert(IN_SET(prop, PROP_VENDOR, PROP_MODEL)); + assert(getter); + + context_read_machine_info(c); + + if (isempty(c->data[prop])) + (void) getter(&from_dmi); + + return sd_bus_message_append(reply, "s", from_dmi ?: c->data[prop]); +} + static int property_get_hardware_vendor( sd_bus *bus, const char *path, @@ -524,10 +549,7 @@ static int property_get_hardware_vendor( void *userdata, sd_bus_error *error) { - _cleanup_free_ char *vendor = NULL; - - (void) get_hardware_vendor(&vendor); - return sd_bus_message_append(reply, "s", vendor); + return property_get_hardware_property(reply, userdata, PROP_VENDOR, get_hardware_vendor); } static int property_get_hardware_model( @@ -539,10 +561,7 @@ static int property_get_hardware_model( void *userdata, sd_bus_error *error) { - _cleanup_free_ char *model = NULL; - - (void) get_hardware_model(&model); - return sd_bus_message_append(reply, "s", model); + return property_get_hardware_property(reply, userdata, PROP_MODEL, get_hardware_model); } static int property_get_hostname( @@ -1087,8 +1106,10 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro assert_se(uname(&u) >= 0); - (void) get_hardware_vendor(&vendor); - (void) get_hardware_model(&model); + if (isempty(c->data[PROP_VENDOR])) + (void) get_hardware_vendor(&vendor); + if (isempty(c->data[PROP_MODEL])) + (void) get_hardware_model(&model); if (privileged) /* The product UUID is only available to privileged clients */ id128_get_product(&product_uuid); @@ -1109,8 +1130,8 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])), JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])), JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])), - JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor)), - JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model)), + JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor ?: c->data[PROP_VENDOR])), + JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model ?: c->data[PROP_MODEL])), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_ID128(product_uuid)), JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_NULL))); From a93306a22efc376cf2389479069ba9dc8875c9e3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 22 Jan 2022 15:20:06 +0900 Subject: [PATCH 3/4] rule: make ID_SYSFS_ATTRIBUTE_MODEL also accept product_name --- rules.d/50-udev-default.rules.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in index 685b59a78a..dcc7a77630 100644 --- a/rules.d/50-udev-default.rules.in +++ b/rules.d/50-udev-default.rules.in @@ -105,7 +105,10 @@ SUBSYSTEM=="ptp", ATTR{clock_name}=="KVM virtual PTP", SYMLINK += "ptp_kvm" SUBSYSTEM=="ptp", ATTR{clock_name}=="hyperv", SYMLINK += "ptp_hyperv" -SUBSYSTEM=="dmi", ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="", ENV{ID_VENDOR}="$attr{sys_vendor}", ENV{ID_MODEL}="$attr{product_name}" -SUBSYSTEM=="dmi", ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="product_version", ENV{ID_VENDOR}="$attr{sys_vendor}", ENV{ID_MODEL}="$attr{product_version}" +SUBSYSTEM!="dmi", GOTO="dmi_end" +ENV{ID_VENDOR}="$attr{sys_vendor}" +ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="|product_name", ENV{ID_MODEL}="$attr{product_name}" +ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="product_version", ENV{ID_MODEL}="$attr{product_version}" +LABEL="dmi_end" LABEL="default_end" From da60d91c9908b33fa6baa10ef80a7adc2312e615 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 12:57:43 +0900 Subject: [PATCH 4/4] rule: fallback to use board information if product information is not set --- rules.d/50-udev-default.rules.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in index dcc7a77630..9cdaadb4cd 100644 --- a/rules.d/50-udev-default.rules.in +++ b/rules.d/50-udev-default.rules.in @@ -109,6 +109,9 @@ SUBSYSTEM!="dmi", GOTO="dmi_end" ENV{ID_VENDOR}="$attr{sys_vendor}" ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="|product_name", ENV{ID_MODEL}="$attr{product_name}" ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="product_version", ENV{ID_MODEL}="$attr{product_version}" +# fallback to board information +ENV{ID_VENDOR}=="", ENV{ID_VENDOR}="$attr{board_vendor}" +ENV{ID_MODEL}=="", ENV{ID_MODEL}="$attr{board_name}" LABEL="dmi_end" LABEL="default_end"