mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-26 09:57:26 +03:00
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.
This commit is contained in:
parent
f9ea108e7c
commit
7871c8e932
@ -80,8 +80,8 @@
|
||||
<para>The static host name is stored in
|
||||
<filename>/etc/hostname</filename>, see
|
||||
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
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
|
||||
<filename>/etc/machine-info</filename>, see
|
||||
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
@ -198,8 +198,34 @@
|
||||
Naming Specification</ulink>. 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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>set-chassis [TYPE]</command></term>
|
||||
|
||||
<listitem><para>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:
|
||||
<literal>desktop</literal>,
|
||||
<literal>laptop</literal>,
|
||||
<literal>server</literal>,
|
||||
<literal>tablet</literal>,
|
||||
<literal>handset</literal>, as well as
|
||||
the special chassis types
|
||||
<literal>vm</literal> and
|
||||
<literal>container</literal> 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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -128,6 +128,34 @@
|
||||
similar icon name.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>CHASSIS=</varname></term>
|
||||
|
||||
<listitem><para>The chassis
|
||||
type. Currently, the following chassis
|
||||
types are defined:
|
||||
<literal>desktop</literal>,
|
||||
<literal>laptop</literal>,
|
||||
<literal>server</literal>,
|
||||
<literal>tablet</literal>,
|
||||
<literal>handset</literal>, as well as
|
||||
the special chassis types
|
||||
<literal>vm</literal> and
|
||||
<literal>container</literal> 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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
@ -135,8 +163,9 @@
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
|
||||
<programlisting>PRETTY_HOSTNAME="Lennart's Computer"
|
||||
ICON_NAME=computer-laptop</programlisting>
|
||||
<programlisting>PRETTY_HOSTNAME="Lennart's Tablet"
|
||||
ICON_NAME=computer-tablet
|
||||
CHASSIS=tablet</programlisting>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
if (detect_virtualization(NULL) > 0)
|
||||
return "computer-vm";
|
||||
v = detect_virtualization(NULL);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
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";
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 7:
|
||||
return "server";
|
||||
|
||||
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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user