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 | |
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')
-rw-r--r-- | src/hostname/hostnamectl.c | 41 | ||||
-rw-r--r-- | src/hostname/hostnamed.c | 141 |
2 files changed, 156 insertions, 26 deletions
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 265c7ecbfe..e38be89b37 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 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)) |