From 7871c8e9327e4e5b18de9d8081b0f32fa38c2c1f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Dec 2012 19:03:59 +0100 Subject: [PATCH] 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. --- man/hostnamectl.xml | 32 ++++++++- man/machine-info.xml | 33 ++++++++- src/hostname/hostnamectl.c | 41 +++++++++-- src/hostname/hostnamed.c | 141 +++++++++++++++++++++++++++++++------ 4 files changed, 216 insertions(+), 31 deletions(-) diff --git a/man/hostnamectl.xml b/man/hostnamectl.xml index c36f522c8..a29d2f5b7 100644 --- a/man/hostnamectl.xml +++ b/man/hostnamectl.xml @@ -80,8 +80,8 @@ The static host name is stored in /etc/hostname, see hostname5 - for more information. The pretty host name and icon - name are stored in + for more information. The pretty host name, chassis + type and icon name are stored in /etc/machine-info, see machine-id5. @@ -198,8 +198,34 @@ Naming Specification. Pass an empty string to this operation to reset the icon name to the default + value which is determined from chassis + type (see below) and possibly other + parameters. + + + + set-chassis [TYPE] + + Set the chassis + type. The chassis type is used by some + graphical applications to visualize + the host or alter user + interaction. Currently, the following + chassis types are defined: + desktop, + laptop, + server, + tablet, + handset, as well as + the special chassis types + vm and + container for + virtualized systems that lack an + immediate physical chassis. Pass an + empty string to this operation to + reset the chassis type to the default value which is determined from the - system form factor and possibly other + firmware and possibly other parameters. diff --git a/man/machine-info.xml b/man/machine-info.xml index b310d7133..1c3a21c64 100644 --- a/man/machine-info.xml +++ b/man/machine-info.xml @@ -128,6 +128,34 @@ similar icon name. + + CHASSIS= + + The chassis + type. Currently, the following chassis + types are defined: + desktop, + laptop, + server, + tablet, + handset, as well as + the special chassis types + vm and + container for + virtualized systems that lack an + immediate physical chassis. Note that + many systems allow detection of the + chassis type automatically (based on + firmware information or + suchlike). This setting (if set) shall + take precedence over automatically + detected information and is useful to + override misdetected configuration or + to manually configure the chassis type + where automatic detection is not + available. + + @@ -135,8 +163,9 @@ Example - PRETTY_HOSTNAME="Lennart's Computer" -ICON_NAME=computer-laptop + PRETTY_HOSTNAME="Lennart's Tablet" +ICON_NAME=computer-tablet +CHASSIS=tablet diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 265c7ecbf..e38be89b3 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -63,6 +63,7 @@ typedef struct StatusInfo { const char *static_hostname; const char *pretty_hostname; const char *icon_name; + const char *chassis; } StatusInfo; static void print_status_info(StatusInfo *i) { @@ -82,9 +83,11 @@ static void print_status_info(StatusInfo *i) { strna(i->hostname)); printf(" Pretty hostname: %s\n" - " Icon name: %s\n", + " Icon name: %s\n" + " Chassis: %s\n", strna(i->pretty_hostname), - strna(i->icon_name)); + strna(i->icon_name), + strna(i->chassis)); r = sd_id128_get_machine(&mid); if (r >= 0) @@ -133,6 +136,8 @@ static int status_property(const char *name, DBusMessageIter *iter, StatusInfo * i->pretty_hostname = s; if (streq(name, "IconName")) i->icon_name = s; + if (streq(name, "Chassis")) + i->chassis = s; } break; } @@ -321,6 +326,28 @@ static int set_icon_name(DBusConnection *bus, char **args, unsigned n) { DBUS_TYPE_INVALID); } +static int set_chassis(DBusConnection *bus, char **args, unsigned n) { + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + dbus_bool_t interactive = true; + + assert(args); + assert(n == 2); + + polkit_agent_open_if_enabled(); + + return bus_method_call_with_reply( + bus, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "SetChassis", + &reply, + NULL, + DBUS_TYPE_STRING, &args[1], + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID); +} + static int help(void) { printf("%s [OPTIONS...] COMMAND ...\n\n" @@ -335,7 +362,8 @@ static int help(void) { "Commands:\n" " status Show current hostname settings\n" " set-hostname NAME Set system hostname\n" - " set-icon-name NAME Set icon name for host\n", + " set-icon-name NAME Set icon name for host\n" + " set-chassis NAME Set chassis type for host\n", program_invocation_short_name); return 0; @@ -434,9 +462,10 @@ static int hostnamectl_main(DBusConnection *bus, int argc, char *argv[], DBusErr const int argc; int (* const dispatch)(DBusConnection *bus, char **args, unsigned n); } verbs[] = { - { "status", LESS, 1, show_status }, - { "set-hostname", EQUAL, 2, set_hostname }, - { "set-icon-name", EQUAL, 2, set_icon_name }, + { "status", LESS, 1, show_status }, + { "set-hostname", EQUAL, 2, set_hostname }, + { "set-icon-name", EQUAL, 2, set_icon_name }, + { "set-chassis", EQUAL, 2, set_chassis }, }; int left; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index cd3ef491a..92b150bfc 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -39,6 +39,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -55,6 +56,10 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \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)) -- 2.30.2