diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-12-24 19:03:59 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-12-24 19:03:59 +0100 |
commit | 7871c8e9327e4e5b18de9d8081b0f32fa38c2c1f (patch) | |
tree | 56dea3f21fcc707ac392696697a50d18c21a09d5 /src/hostname/hostnamed.c | |
parent | f9ea108e7c3544c03822277a1112a48dc62f6ed4 (diff) |
hostnamed: make chassis type configurable via /etc/machine-info
For many usecases it is useful to store the chassis type somewhere, and
/etc/machine-info sounds like a good place. Ideally we could always
detect the chassis type from firmware, but frequently that's not
available and in many embedded devices probably entirely unrealistic.
This patch adds a configurable setting CHASSIS= to /etc/machine-info and
exposes this via hostnamectl/hostnamed. hostnamed will guess the chassis
type from DMI if nothing is set explicitly. I also added support for
detecting it from ACPI, which should be more useful as ACPI 5.0 actually
knows a "tablet" chassis type, which neither DMI nor previous ACPI
versions knew.
This also enables DMI-based and ACPI-based detection for non-x86 systems
as ACPI is apparently coming to ARM platforms soon.
I tried to minimize the vocabulary of chassis types understood and
added: desktop, laptop, server, tablet, handset. This is much less than
either APCI or DMI know. If we need more types later on we can easily
add them.
Diffstat (limited to 'src/hostname/hostnamed.c')
-rw-r--r-- | src/hostname/hostnamed.c | 141 |
1 files changed, 121 insertions, 20 deletions
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index cd3ef491ac..92b150bfc9 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -39,6 +39,7 @@ " <property name=\"StaticHostname\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"PrettyHostname\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"IconName\" type=\"s\" access=\"read\"/>\n" \ + " <property name=\"Chassis\" type=\"s\" access=\"read\"/>\n" \ " <method name=\"SetHostname\">\n" \ " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ @@ -55,6 +56,10 @@ " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ " </method>\n" \ + " <method name=\"SetChassis\">\n" \ + " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ + " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ + " </method>\n" \ " </interface>\n" #define INTROSPECTION \ @@ -77,6 +82,7 @@ enum { PROP_STATIC_HOSTNAME, PROP_PRETTY_HOSTNAME, PROP_ICON_NAME, + PROP_CHASSIS, _PROP_MAX }; @@ -84,6 +90,7 @@ static char *data[_PROP_MAX] = { NULL, NULL, NULL, + NULL, NULL }; @@ -114,6 +121,7 @@ static int read_data(void) { r = parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &data[PROP_PRETTY_HOSTNAME], "ICON_NAME", &data[PROP_ICON_NAME], + "CHASSIS", &data[PROP_CHASSIS], NULL); if (r < 0 && r != -ENOENT) return r; @@ -122,10 +130,10 @@ static int read_data(void) { } static bool check_nss(void) { - void *dl; - if ((dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY))) { + dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY); + if (dl) { dlclose(dl); return true; } @@ -133,25 +141,77 @@ static bool check_nss(void) { return false; } -static const char* fallback_icon_name(void) { +static bool valid_chassis(const char *chassis) { -#if defined(__i386__) || defined(__x86_64__) + assert(chassis); + + return nulstr_contains( + "vm\0" + "container\0" + "desktop\0" + "laptop\0" + "server\0" + "tablet\0" + "handset\0", + chassis); +} + +static const char* fallback_chassis(void) { int r; char *type; unsigned t; -#endif + Virtualization v; + + v = detect_virtualization(NULL); + + if (v == VIRTUALIZATION_VM) + return "vm"; + if (v == VIRTUALIZATION_CONTAINER) + return "container"; + + r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type); + if (r < 0) + goto try_dmi; + + r = safe_atou(type, &t); + free(type); + if (r < 0) + goto try_dmi; + + /* We only list the really obvious cases here as the ACPI data + * is not really super reliable. + * + * See the ACPI 5.0 Spec Section 5.2.9.1 for details: + * + * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf + */ + + switch(t) { + + case 1: + case 3: + case 6: + return "desktop"; + + case 2: + return "laptop"; - if (detect_virtualization(NULL) > 0) - return "computer-vm"; + case 4: + case 5: + case 7: + return "server"; -#if defined(__i386__) || defined(__x86_64__) + case 8: + return "tablet"; + } + +try_dmi: r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type); if (r < 0) return NULL; r = safe_atou(type, &t); free(type); - if (r < 0) return NULL; @@ -171,22 +231,38 @@ static const char* fallback_icon_name(void) { case 0x4: case 0x6: case 0x7: - return "computer-desktop"; + return "desktop"; + case 0x8: case 0x9: case 0xA: case 0xE: - return "computer-laptop"; + return "laptop"; + + case 0xB: + return "handset"; case 0x11: case 0x1C: - return "computer-server"; + return "server"; } -#endif return NULL; } +static char* fallback_icon_name(void) { + const char *chassis; + + if (!isempty(data[PROP_CHASSIS])) + return strappend("computer-", data[PROP_CHASSIS]); + + chassis = fallback_chassis(); + if (chassis) + return strappend("computer-", chassis); + + return strdup("computer"); +} + static int write_data_hostname(void) { const char *hn; @@ -218,7 +294,8 @@ static int write_data_other(void) { static const char * const name[_PROP_MAX] = { [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", - [PROP_ICON_NAME] = "ICON_NAME" + [PROP_ICON_NAME] = "ICON_NAME", + [PROP_CHASSIS] = "CHASSIS" }; char **l = NULL; @@ -268,23 +345,39 @@ static int write_data_other(void) { static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) { const char *name; + _cleanup_free_ char *n = NULL; assert(i); assert(property); if (isempty(data[PROP_ICON_NAME])) - name = fallback_icon_name(); + name = n = fallback_icon_name(); else name = data[PROP_ICON_NAME]; return bus_property_append_string(i, property, (void*) name); } +static int bus_hostname_append_chassis(DBusMessageIter *i, const char *property, void *userdata) { + const char *name; + + assert(i); + assert(property); + + if (isempty(data[PROP_CHASSIS])) + name = fallback_chassis(); + else + name = data[PROP_CHASSIS]; + + return bus_property_append_string(i, property, (void*) name); +} + static const BusProperty bus_hostname_properties[] = { { "Hostname", bus_property_append_string, "s", sizeof(data[0])*PROP_HOSTNAME, true }, { "StaticHostname", bus_property_append_string, "s", sizeof(data[0])*PROP_STATIC_HOSTNAME, true }, { "PrettyHostname", bus_property_append_string, "s", sizeof(data[0])*PROP_PRETTY_HOSTNAME, true }, { "IconName", bus_hostname_append_icon_name, "s", sizeof(data[0])*PROP_ICON_NAME, true }, + { "Chassis", bus_hostname_append_chassis, "s", sizeof(data[0])*PROP_CHASSIS, true }, { NULL, } }; @@ -414,7 +507,8 @@ static DBusHandlerResult hostname_message_handler( } } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetPrettyHostname") || - dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName")) { + dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName") || + dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetChassis")) { const char *name; dbus_bool_t interactive; @@ -431,7 +525,8 @@ static DBusHandlerResult hostname_message_handler( if (isempty(name)) name = NULL; - k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : PROP_ICON_NAME; + k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : + streq(dbus_message_get_member(message), "SetChassis") ? PROP_CHASSIS : PROP_ICON_NAME; if (!streq_ptr(name, data[k])) { @@ -458,6 +553,8 @@ static DBusHandlerResult hostname_message_handler( return bus_send_error_reply(connection, message, NULL, -EINVAL); if (k == PROP_PRETTY_HOSTNAME && !string_is_safe(name)) return bus_send_error_reply(connection, message, NULL, -EINVAL); + if (k == PROP_CHASSIS && !valid_chassis(name)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); h = strdup(name); if (!h) @@ -473,12 +570,15 @@ static DBusHandlerResult hostname_message_handler( return bus_send_error_reply(connection, message, NULL, r); } - log_info("Changed %s to '%s'", k == PROP_PRETTY_HOSTNAME ? "pretty host name" : "icon name", strempty(data[k])); + log_info("Changed %s to '%s'", + k == PROP_PRETTY_HOSTNAME ? "pretty host name" : + k == PROP_CHASSIS ? "chassis" : "icon name", strempty(data[k])); changed = bus_properties_changed_new( "/org/freedesktop/hostname1", "org.freedesktop.hostname1", - k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : "IconName\0"); + k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : + k == PROP_CHASSIS ? "Chassis\0" : "IconName\0"); if (!changed) goto oom; } @@ -486,7 +586,8 @@ static DBusHandlerResult hostname_message_handler( } else return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps); - if (!(reply = dbus_message_new_method_return(message))) + reply = dbus_message_new_method_return(message); + if (!reply) goto oom; if (!dbus_connection_send(connection, reply, NULL)) |