mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
Merge pull request #19451 from poettering/hostnamed-json
hostnamed: add JSON output to hostnamectl
This commit is contained in:
commit
34bcc67681
@ -195,6 +195,7 @@
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -58,6 +58,7 @@ node /org/freedesktop/hostname1 {
|
||||
in b interactive);
|
||||
GetProductUUID(in b interactive,
|
||||
out ay uuid);
|
||||
Describe(out s UNNAMED);
|
||||
properties:
|
||||
readonly s Hostname = '...';
|
||||
readonly s StaticHostname = '...';
|
||||
@ -118,6 +119,8 @@ node /org/freedesktop/hostname1 {
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="GetProductUUID()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="Describe()"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Hostname"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="StaticHostname"/>
|
||||
@ -232,6 +235,17 @@ node /org/freedesktop/hostname1 {
|
||||
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
for that. For more information on these files and syscalls see the respective man pages.</para>
|
||||
|
||||
<para><varname>KernelName</varname>, <varname>KernelRelease</varname>, and
|
||||
<varname>KernelVersion</varname> expose the kernel name (e.g. <literal>Linux</literal>), release
|
||||
(e.g. <literal>5.0.0-11</literal>), and version (i.e. the build number, e.g. <literal>#11</literal>) as
|
||||
reported by <citerefentry project="man-pages"><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
|
||||
<varname>OperatingSystemPrettyName</varname>, <varname>OperatingSystemCPEName</varname>, and
|
||||
<varname>HomeURL</varname> expose the <varname>PRETTY_NAME=</varname>, <varname>CPE_NAME=</varname> and
|
||||
<varname>HOME_URL=</varname> fields from
|
||||
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>. The
|
||||
purpose of those properties is to allow remote clients to access this information over D-Bus. Local
|
||||
clients can access the information directly.</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Methods</title>
|
||||
|
||||
@ -261,22 +275,12 @@ node /org/freedesktop/hostname1 {
|
||||
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
the semantics of those settings.</para>
|
||||
|
||||
<para><function>GetProductUUID()</function> returns the "product uuid" as exposed by the kernel based
|
||||
<para><function>GetProductUUID()</function> returns the "product UUID" as exposed by the kernel based
|
||||
on DMI information in <filename>/sys/class/dmi/id/product_uuid</filename>. Reading the file directly
|
||||
requires root privileges, and this method allows access to unprivileged clients through the polkit
|
||||
framework.</para>
|
||||
|
||||
<para><varname>KernelName</varname>, <varname>KernelRelease</varname>, and
|
||||
<varname>KernelVersion</varname> expose the kernel name (e.g. <literal>Linux</literal>), release
|
||||
(e.g. <literal>5.0.0-11</literal>), and version (i.e. the build number, e.g. <literal>#11</literal>) as
|
||||
reported by
|
||||
<citerefentry project="man-pages"><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
|
||||
<varname>OperatingSystemPrettyName</varname>, <varname>OperatingSystemCPEName</varname>, and
|
||||
<varname>HomeURL</varname> expose the <varname>PRETTY_NAME=</varname>, <varname>CPE_NAME=</varname> and
|
||||
<varname>HOME_URL=</varname> fields from
|
||||
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>. The
|
||||
purpose of those properties is to allow remote clients to access this information over D-Bus. Local
|
||||
clients can access the information directly.</para>
|
||||
<para><function>Describe()</function> returns a JSON representation of all properties in one.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
|
@ -17,7 +17,9 @@
|
||||
#include "format-table.h"
|
||||
#include "hostname-setup.h"
|
||||
#include "hostname-util.h"
|
||||
#include "json.h"
|
||||
#include "main-func.h"
|
||||
#include "parse-argument.h"
|
||||
#include "pretty-print.h"
|
||||
#include "spawn-polkit-agent.h"
|
||||
#include "terminal-util.h"
|
||||
@ -30,6 +32,7 @@ static char *arg_host = NULL;
|
||||
static bool arg_transient = false;
|
||||
static bool arg_pretty = false;
|
||||
static bool arg_static = false;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
|
||||
typedef struct StatusInfo {
|
||||
const char *hostname;
|
||||
@ -317,6 +320,37 @@ static int show_all_names(sd_bus *bus) {
|
||||
|
||||
static int show_status(int argc, char **argv, void *userdata) {
|
||||
sd_bus *bus = userdata;
|
||||
int r;
|
||||
|
||||
if (arg_json_format_flags != JSON_FORMAT_OFF) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
const char *text = NULL;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.hostname1",
|
||||
"/org/freedesktop/hostname1",
|
||||
"org.freedesktop.hostname1",
|
||||
"Describe",
|
||||
&error,
|
||||
&reply,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get description: %s", bus_error_message(&error, r));
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &text);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = json_parse(text, 0, &v, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse JSON: %m");
|
||||
|
||||
json_variant_dump(v, arg_json_format_flags, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_pretty || arg_static || arg_transient) {
|
||||
const char *attr;
|
||||
@ -489,6 +523,8 @@ static int help(void) {
|
||||
" --transient Only set transient hostname\n"
|
||||
" --static Only set static hostname\n"
|
||||
" --pretty Only set pretty hostname\n"
|
||||
" --json=pretty|short|off\n"
|
||||
" Generate JSON output\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
@ -509,7 +545,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_NO_ASK_PASSWORD,
|
||||
ARG_TRANSIENT,
|
||||
ARG_STATIC,
|
||||
ARG_PRETTY
|
||||
ARG_PRETTY,
|
||||
ARG_JSON,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -521,10 +558,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "host", required_argument, NULL, 'H' },
|
||||
{ "machine", required_argument, NULL, 'M' },
|
||||
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
@ -565,6 +603,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_ask_password = false;
|
||||
break;
|
||||
|
||||
case ARG_JSON:
|
||||
r = parse_json_argument(optarg, &arg_json_format_flags);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "hostname-setup.h"
|
||||
#include "hostname-util.h"
|
||||
#include "id128-util.h"
|
||||
#include "json.h"
|
||||
#include "main-func.h"
|
||||
#include "missing_capability.h"
|
||||
#include "nscd-flush.h"
|
||||
@ -40,6 +41,8 @@
|
||||
|
||||
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
|
||||
|
||||
/* Properties we cache are indexed by an enum, to make invalidation easy and systematic (as we can iterate
|
||||
* through them all, and they are uniformly strings). */
|
||||
enum {
|
||||
/* Read from /etc/hostname */
|
||||
PROP_STATIC_HOSTNAME,
|
||||
@ -51,9 +54,6 @@ enum {
|
||||
PROP_DEPLOYMENT,
|
||||
PROP_LOCATION,
|
||||
|
||||
PROP_HARDWARE_VENDOR,
|
||||
PROP_HARDWARE_MODEL,
|
||||
|
||||
/* Read from /etc/os-release (or /usr/lib/os-release) */
|
||||
PROP_OS_PRETTY_NAME,
|
||||
PROP_OS_CPE_NAME,
|
||||
@ -449,6 +449,41 @@ static int context_write_data_machine_info(Context *c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
_cleanup_free_ char *b = NULL;
|
||||
const char *s = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
|
||||
|
||||
if (database_key)
|
||||
(void) sd_device_get_property_value(device, database_key, &s);
|
||||
if (!s && regular_key)
|
||||
(void) sd_device_get_property_value(device, regular_key, &s);
|
||||
|
||||
if (s) {
|
||||
b = strdup(s);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(b);
|
||||
|
||||
return !!s;
|
||||
}
|
||||
|
||||
static int get_hardware_vendor(char **ret) {
|
||||
return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret);
|
||||
}
|
||||
|
||||
static int get_hardware_model(char **ret) {
|
||||
return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret);
|
||||
}
|
||||
|
||||
static int property_get_hardware_vendor(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
@ -457,20 +492,11 @@ static int property_get_hardware_vendor(
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
const char *hardware_vendor = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
|
||||
return sd_bus_message_append(reply, "s", NULL);
|
||||
}
|
||||
_cleanup_free_ char *vendor = NULL;
|
||||
|
||||
if (sd_device_get_property_value(device, "ID_VENDOR_FROM_DATABASE", &hardware_vendor) < 0)
|
||||
(void) sd_device_get_property_value(device, "ID_VENDOR", &hardware_vendor);
|
||||
|
||||
return sd_bus_message_append(reply, "s", hardware_vendor);
|
||||
(void) get_hardware_vendor(&vendor);
|
||||
return sd_bus_message_append(reply, "s", vendor);
|
||||
}
|
||||
|
||||
static int property_get_hardware_model(
|
||||
@ -481,20 +507,11 @@ static int property_get_hardware_model(
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
const char *hardware_model = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
|
||||
return sd_bus_message_append(reply, "s", NULL);
|
||||
}
|
||||
_cleanup_free_ char *model = NULL;
|
||||
|
||||
if (sd_device_get_property_value(device, "ID_MODEL_FROM_DATABASE", &hardware_model) < 0)
|
||||
(void) sd_device_get_property_value(device, "ID_MODEL", &hardware_model);
|
||||
|
||||
return sd_bus_message_append(reply, "s", hardware_model);
|
||||
(void) get_hardware_model(&model);
|
||||
return sd_bus_message_append(reply, "s", model);
|
||||
}
|
||||
|
||||
static int property_get_hostname(
|
||||
@ -548,13 +565,46 @@ static int property_get_default_hostname(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_free_ char *hn = get_default_hostname();
|
||||
_cleanup_free_ char *hn = NULL;
|
||||
|
||||
hn = get_default_hostname();
|
||||
if (!hn)
|
||||
return log_oom();
|
||||
|
||||
return sd_bus_message_append(reply, "s", hn);
|
||||
}
|
||||
|
||||
static void context_determine_hostname_source(Context *c) {
|
||||
char hostname[HOST_NAME_MAX + 1] = {};
|
||||
_cleanup_free_ char *fallback = NULL;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (c->hostname_source >= 0)
|
||||
return;
|
||||
|
||||
(void) get_hostname_filtered(hostname);
|
||||
|
||||
if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
|
||||
c->hostname_source = HOSTNAME_STATIC;
|
||||
else {
|
||||
/* If the hostname was not set by us, try to figure out where it came from. If we set it to
|
||||
* the default hostname, the file will tell us. We compare the string because it is possible
|
||||
* that the hostname was set by an older version that had a different fallback, in the
|
||||
* initramfs or before we reexecuted. */
|
||||
|
||||
r = read_one_line_file("/run/systemd/default-hostname", &fallback);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
|
||||
|
||||
if (streq_ptr(fallback, hostname))
|
||||
c->hostname_source = HOSTNAME_DEFAULT;
|
||||
else
|
||||
c->hostname_source = HOSTNAME_TRANSIENT;
|
||||
}
|
||||
}
|
||||
|
||||
static int property_get_hostname_source(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
@ -565,36 +615,10 @@ static int property_get_hostname_source(
|
||||
sd_bus_error *error) {
|
||||
|
||||
Context *c = userdata;
|
||||
int r;
|
||||
assert(c);
|
||||
|
||||
context_read_etc_hostname(c);
|
||||
|
||||
if (c->hostname_source < 0) {
|
||||
char hostname[HOST_NAME_MAX + 1] = {};
|
||||
_cleanup_free_ char *fallback = NULL;
|
||||
|
||||
(void) get_hostname_filtered(hostname);
|
||||
|
||||
if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
|
||||
c->hostname_source = HOSTNAME_STATIC;
|
||||
|
||||
else {
|
||||
/* If the hostname was not set by us, try to figure out where it came from. If we set
|
||||
* it to the default hostname, the file will tell us. We compare the string because
|
||||
* it is possible that the hostname was set by an older version that had a different
|
||||
* fallback, in the initramfs or before we reexecuted. */
|
||||
|
||||
r = read_one_line_file("/run/systemd/default-hostname", &fallback);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
|
||||
|
||||
if (streq_ptr(fallback, hostname))
|
||||
c->hostname_source = HOSTNAME_DEFAULT;
|
||||
else
|
||||
c->hostname_source = HOSTNAME_TRANSIENT;
|
||||
}
|
||||
}
|
||||
context_determine_hostname_source(c);
|
||||
|
||||
return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
|
||||
}
|
||||
@ -932,28 +956,12 @@ static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *
|
||||
static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Context *c = userdata;
|
||||
bool has_uuid = false;
|
||||
int interactive, r;
|
||||
sd_id128_t uuid;
|
||||
|
||||
assert(m);
|
||||
assert(c);
|
||||
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
|
||||
if (r == -ENOENT)
|
||||
r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
|
||||
if (r < 0)
|
||||
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to read product UUID, ignoring: %m");
|
||||
else if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
|
||||
log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(uuid));
|
||||
else
|
||||
has_uuid = true;
|
||||
|
||||
if (!has_uuid)
|
||||
return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
|
||||
"Failed to read product UUID from firmware.");
|
||||
|
||||
r = sd_bus_message_read(m, "b", &interactive);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -972,11 +980,125 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
r = id128_get_product(&uuid);
|
||||
if (r < 0) {
|
||||
if (r == -EADDRNOTAVAIL)
|
||||
log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
|
||||
else
|
||||
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to read product UUID, ignoring: %m");
|
||||
|
||||
return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
|
||||
"Failed to read product UUID from firmware.");
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_method_return(m, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append_array(reply, 'y', &uuid, sizeof(uuid));
|
||||
r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL, *vendor = NULL, *model = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
sd_id128_t product_uuid = SD_ID128_NULL;
|
||||
const char *chassis = NULL;
|
||||
Context *c = userdata;
|
||||
bool privileged;
|
||||
struct utsname u;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(c);
|
||||
|
||||
r = bus_verify_polkit_async(
|
||||
m,
|
||||
CAP_SYS_ADMIN,
|
||||
"org.freedesktop.hostname1.get-product-uuid",
|
||||
NULL,
|
||||
false,
|
||||
UID_INVALID,
|
||||
&c->polkit_registry,
|
||||
NULL);
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
/* We ignore all authentication errors here, since most data is unprivileged, the one exception being
|
||||
* the product ID which we'll check explicitly. */
|
||||
privileged = r > 0;
|
||||
|
||||
context_read_etc_hostname(c);
|
||||
context_read_machine_info(c);
|
||||
context_read_os_release(c);
|
||||
context_determine_hostname_source(c);
|
||||
|
||||
r = gethostname_strict(&hn);
|
||||
if (r < 0) {
|
||||
if (r != -ENXIO)
|
||||
return log_error_errno(r, "Failed to read local host name: %m");
|
||||
|
||||
hn = get_default_hostname();
|
||||
if (!hn)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
dhn = get_default_hostname();
|
||||
if (!dhn)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(c->data[PROP_ICON_NAME]))
|
||||
in = context_fallback_icon_name(c);
|
||||
|
||||
if (isempty(c->data[PROP_CHASSIS]))
|
||||
chassis = fallback_chassis();
|
||||
|
||||
assert_se(uname(&u) >= 0);
|
||||
|
||||
(void) get_hardware_vendor(&vendor);
|
||||
(void) get_hardware_model(&model);
|
||||
|
||||
if (privileged) /* The product UUID is only available to privileged clients */
|
||||
id128_get_product(&product_uuid);
|
||||
|
||||
r = json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn)),
|
||||
JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])),
|
||||
JSON_BUILD_PAIR("PrettyHostname", JSON_BUILD_STRING(c->data[PROP_PRETTY_HOSTNAME])),
|
||||
JSON_BUILD_PAIR("DefaultHostname", JSON_BUILD_STRING(dhn)),
|
||||
JSON_BUILD_PAIR("HostnameSource", JSON_BUILD_STRING(hostname_source_to_string(c->hostname_source))),
|
||||
JSON_BUILD_PAIR("IconName", JSON_BUILD_STRING(in ?: c->data[PROP_ICON_NAME])),
|
||||
JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis ?: c->data[PROP_CHASSIS])),
|
||||
JSON_BUILD_PAIR("Deployment", JSON_BUILD_STRING(c->data[PROP_DEPLOYMENT])),
|
||||
JSON_BUILD_PAIR("Location", JSON_BUILD_STRING(c->data[PROP_LOCATION])),
|
||||
JSON_BUILD_PAIR("KernelName", JSON_BUILD_STRING(u.sysname)),
|
||||
JSON_BUILD_PAIR("KernelRelease", JSON_BUILD_STRING(u.release)),
|
||||
JSON_BUILD_PAIR("KernelVersion", JSON_BUILD_STRING(u.version)),
|
||||
JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])),
|
||||
JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])),
|
||||
JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])),
|
||||
JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor)),
|
||||
JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model)),
|
||||
JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_ID128(product_uuid)),
|
||||
JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_NULL)));
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON data: %m");
|
||||
|
||||
r = json_variant_format(v, 0, &text);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format JSON data: %m");
|
||||
|
||||
r = sd_bus_message_new_method_return(m, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_append(reply, "s", text);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1059,6 +1181,11 @@ static const sd_bus_vtable hostname_vtable[] = {
|
||||
SD_BUS_PARAM(uuid),
|
||||
method_get_product_uuid,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("Describe",
|
||||
SD_BUS_NO_ARGS,
|
||||
SD_BUS_RESULT("s", json),
|
||||
method_describe,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
@ -210,3 +210,25 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
|
||||
|
||||
int id128_get_product(sd_id128_t *ret) {
|
||||
sd_id128_t uuid;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
/* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
|
||||
* particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
|
||||
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
|
||||
if (r == -ENOENT)
|
||||
r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
|
||||
return -EADDRNOTAVAIL; /* Recognizable error */
|
||||
|
||||
*ret = uuid;
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,3 +36,5 @@ int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
|
||||
extern const struct hash_ops id128_hash_ops;
|
||||
|
||||
sd_id128_t id128_make_v4_uuid(sd_id128_t id);
|
||||
|
||||
int id128_get_product(sd_id128_t *ret);
|
||||
|
@ -62,16 +62,10 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
|
||||
|
||||
} else if (detect_vm() == VIRTUALIZATION_KVM) {
|
||||
|
||||
/* If we are not running in a container, see if we are
|
||||
* running in qemu/kvm and a machine ID was passed in
|
||||
* via -uuid on the qemu/kvm command line */
|
||||
/* If we are not running in a container, see if we are running in qemu/kvm and a
|
||||
* machine ID was passed in via -uuid on the qemu/kvm command line */
|
||||
|
||||
if (id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, ret) >= 0) {
|
||||
log_info("Initializing machine ID from KVM UUID.");
|
||||
return 0;
|
||||
}
|
||||
/* on POWER, it's exported here instead */
|
||||
if (id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, ret) >= 0) {
|
||||
if (id128_get_product(ret) >= 0) {
|
||||
log_info("Initializing machine ID from KVM UUID.");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user