From: seaeunlee Date: Fri, 6 Mar 2026 00:33:01 +0000 (+0000) Subject: hostname: add API for getting custom fields from machine-info X-Git-Tag: v261-rc1~805 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=59aed18d69c83759a3b05265d3995cff9efe7e84;p=thirdparty%2Fsystemd.git hostname: add API for getting custom fields from machine-info --- diff --git a/man/org.freedesktop.hostname1.xml b/man/org.freedesktop.hostname1.xml index c70258459c2..3d98b88ebc1 100644 --- a/man/org.freedesktop.hostname1.xml +++ b/man/org.freedesktop.hostname1.xml @@ -60,6 +60,8 @@ node /org/freedesktop/hostname1 { out ay uuid); GetHardwareSerial(out s serial); Describe(out s json); + GetMachineInfo(in s field, + out s value); properties: readonly s Hostname = '...'; readonly s StaticHostname = '...'; @@ -146,6 +148,8 @@ node /org/freedesktop/hostname1 { + + @@ -377,6 +381,13 @@ node /org/freedesktop/hostname1 { access to unprivileged clients through the polkit framework. Describe() returns a JSON representation of all properties in one. + + GetMachineInfo() returns the value of the given field from + /etc/machine-info. For well-known fields, this method reads values from the same + internal cache used by the corresponding D-Bus property getters, but returns only the raw + /etc/machine-info values (i.e. without property-level fallback logic such as + DMI/chassis-based detection). Custom (non-standard) fields are read directly from the file. + An error is returned if the field name is empty, invalid, or not set in the file. @@ -494,6 +505,7 @@ node /org/freedesktop/hostname1 { OperatingSystemImageVersion, HardwareSKU, and HardwareVersion were added in version 258. OperatingSystemFancyName was added in version 260. + GetMachineInfo() was added in version 261. diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 04c72e8137b..ce718716183 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -1652,6 +1652,65 @@ static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_ return sd_bus_reply_method_return(m, "s", serial); } +static int method_get_machine_info(sd_bus_message *m, void *userdata, sd_bus_error *error) { + static const struct { + const char *name; + HostProperty prop; + } field_table[] = { + { "PRETTY_HOSTNAME", PROP_PRETTY_HOSTNAME }, + { "ICON_NAME", PROP_ICON_NAME }, + { "CHASSIS", PROP_CHASSIS }, + { "DEPLOYMENT", PROP_DEPLOYMENT }, + { "LOCATION", PROP_LOCATION }, + { "HARDWARE_VENDOR", PROP_HARDWARE_VENDOR }, + { "HARDWARE_MODEL", PROP_HARDWARE_MODEL }, + { "HARDWARE_SKU", PROP_HARDWARE_SKU }, + { "HARDWARE_VERSION", PROP_HARDWARE_VERSION }, + }; + + Context *c = ASSERT_PTR(userdata); + const char *field; + int r; + + assert(m); + + r = sd_bus_message_read(m, "s", &field); + if (r < 0) + return r; + + if (isempty(field)) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Field name must not be empty."); + + if (!env_name_is_valid(field)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid field name '%s'.", field); + + FOREACH_ELEMENT(e, field_table) + if (streq(field, e->name)) { + /* For fields that are also exposed as D-Bus properties, use the same Context cache as the + * property getters. Note that this returns the raw /etc/machine-info value only: property-level + * fallback logic (e.g. DMI/chassis-based synthesis) is not applied here. For custom/unknown + * fields, fall back to reading the file directly. */ + context_read_machine_info(c); + + if (isempty(c->data[e->prop])) + return sd_bus_error_setf(error, BUS_ERROR_FIELD_NOT_SET, "Field '%s' is not set or empty in /etc/machine-info.", field); + + return sd_bus_reply_method_return(m, "s", c->data[e->prop]); + } + + _cleanup_free_ char *value = NULL; + + r = parse_env_file(NULL, etc_machine_info(), + field, &value); + if (r < 0 && r != -ENOENT) + return sd_bus_error_set_errnof(error, r, "Failed to read /etc/machine-info: %m"); + + if (isempty(value)) + return sd_bus_error_setf(error, BUS_ERROR_FIELD_NOT_SET, "Field '%s' is not set or empty in /etc/machine-info.", field); + + return sd_bus_reply_method_return(m, "s", value); +} + 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, @@ -1883,6 +1942,11 @@ static const sd_bus_vtable hostname_vtable[] = { SD_BUS_RESULT("s", json), method_describe, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetMachineInfo", + SD_BUS_ARGS("s", field), + SD_BUS_RESULT("s", value), + method_get_machine_info, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index f0fc09f8a91..6c2b0fd8814 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -111,6 +111,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP), SD_BUS_ERROR_MAP(BUS_ERROR_NO_HARDWARE_SERIAL, EOPNOTSUPP), + SD_BUS_ERROR_MAP(BUS_ERROR_FIELD_NOT_SET, ENODATA), SD_BUS_ERROR_MAP(BUS_ERROR_FILE_IS_PROTECTED, EACCES), SD_BUS_ERROR_MAP(BUS_ERROR_READ_ONLY_FILESYSTEM, EROFS), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 36676e83db5..b4788433bfc 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -112,6 +112,7 @@ #define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID" #define BUS_ERROR_NO_HARDWARE_SERIAL "org.freedesktop.hostname1.NoHardwareSerial" +#define BUS_ERROR_FIELD_NOT_SET "org.freedesktop.hostname1.FieldNotSet" #define BUS_ERROR_FILE_IS_PROTECTED "org.freedesktop.hostname1.FileIsProtected" #define BUS_ERROR_READ_ONLY_FILESYSTEM "org.freedesktop.hostname1.ReadOnlyFilesystem" diff --git a/test/units/TEST-71-HOSTNAME.sh b/test/units/TEST-71-HOSTNAME.sh index ffb110be688..9bd743dcaa6 100755 --- a/test/units/TEST-71-HOSTNAME.sh +++ b/test/units/TEST-71-HOSTNAME.sh @@ -320,6 +320,74 @@ EOF assert_in "CHASSIS=watch" "$(cat /run/alternate-path/mymachine-info)" } +testcase_get_machine_info() { + if [[ -f /etc/machine-info ]]; then + cp /etc/machine-info /tmp/machine-info.bak + fi + + trap restore_machine_info RETURN + + # Test all standard cached fields + cat >/etc/machine-info </etc/machine-info <