mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
hostnamed: add simple Varlink API, too
This commit is contained in:
parent
09c7bead29
commit
0a6598bb38
@ -38,6 +38,7 @@
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
#include "varlink-io.systemd.Hostname.h"
|
||||
#include "virt.h"
|
||||
|
||||
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
|
||||
@ -77,6 +78,7 @@ typedef struct Context {
|
||||
|
||||
sd_event *event;
|
||||
sd_bus *bus;
|
||||
VarlinkServer *varlink_server;
|
||||
Hashmap *polkit_registry;
|
||||
} Context;
|
||||
|
||||
@ -98,6 +100,7 @@ static void context_destroy(Context *c) {
|
||||
hashmap_free(c->polkit_registry);
|
||||
sd_event_unref(c->event);
|
||||
sd_bus_flush_close_unref(c->bus);
|
||||
varlink_server_unref(c->varlink_server);
|
||||
}
|
||||
|
||||
static void context_read_etc_hostname(Context *c) {
|
||||
@ -1347,34 +1350,19 @@ static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_
|
||||
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,
|
||||
static int build_describe_response(Context *c, bool privileged, JsonVariant **ret) {
|
||||
_cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL,
|
||||
*chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
|
||||
*firmware_vendor = NULL;
|
||||
usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
sd_id128_t machine_id, boot_id, product_uuid = SD_ID128_NULL;
|
||||
unsigned local_cid = VMADDR_CID_ANY;
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
bool privileged;
|
||||
struct utsname u;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = bus_verify_polkit_async(
|
||||
m,
|
||||
"org.freedesktop.hostname1.get-description",
|
||||
/* details= */ NULL,
|
||||
&c->polkit_registry,
|
||||
error);
|
||||
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;
|
||||
assert(c);
|
||||
assert(ret);
|
||||
|
||||
context_read_etc_hostname(c);
|
||||
context_read_machine_info(c);
|
||||
@ -1457,10 +1445,40 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro
|
||||
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),
|
||||
JSON_BUILD_PAIR_CONDITION(local_cid != VMADDR_CID_ANY, "VSockCID", JSON_BUILD_UNSIGNED(local_cid))));
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON data: %m");
|
||||
|
||||
*ret = TAKE_PTR(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ char *text = NULL;
|
||||
bool privileged;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = bus_verify_polkit_async(
|
||||
m,
|
||||
"org.freedesktop.hostname1.get-description",
|
||||
/* details= */ NULL,
|
||||
&c->polkit_registry,
|
||||
error);
|
||||
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;
|
||||
|
||||
r = build_describe_response(c, privileged, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_variant_format(v, 0, &text);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format JSON data: %m");
|
||||
@ -1564,7 +1582,6 @@ static const BusObjectImplementation manager_object = {
|
||||
};
|
||||
|
||||
static int connect_bus(Context *c) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
@ -1594,6 +1611,87 @@ static int connect_bus(Context *c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl_method_describe(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
VARLINK_DISPATCH_POLKIT_FIELD,
|
||||
{}
|
||||
};
|
||||
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
bool privileged;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(parameters);
|
||||
|
||||
r = varlink_dispatch(link, parameters, dispatch_table, /* userdata= */ NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = varlink_verify_polkit_async(
|
||||
link,
|
||||
c->bus,
|
||||
"org.freedesktop.hostname1.get-hardware-serial",
|
||||
/* details= */ NULL,
|
||||
/* good_user= */ UID_INVALID,
|
||||
&c->polkit_registry);
|
||||
if (r == 0)
|
||||
return 0; /* 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;
|
||||
|
||||
if (json_variant_elements(parameters) > 0)
|
||||
return varlink_error_invalid_parameter(link, parameters);
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
r = build_describe_response(c, privileged, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return varlink_reply(link, v);
|
||||
}
|
||||
|
||||
static int connect_varlink(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(c->event);
|
||||
assert(!c->varlink_server);
|
||||
|
||||
r = varlink_server_new(&c->varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
||||
|
||||
varlink_server_set_userdata(c->varlink_server, c);
|
||||
|
||||
r = varlink_server_add_interface(c->varlink_server, &vl_interface_io_systemd_Hostname);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add Hostname interface to varlink server: %m");
|
||||
|
||||
r = varlink_server_bind_method_many(
|
||||
c->varlink_server,
|
||||
"io.systemd.Hostname.Describe", vl_method_describe);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind Varlink method calls: %m");
|
||||
|
||||
r = varlink_server_attach_event(c->varlink_server, c->event, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach Varlink server to event loop: %m");
|
||||
|
||||
r = varlink_server_listen_auto(c->varlink_server);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind to passed Varlink sockets: %m");
|
||||
if (r == 0) {
|
||||
r = varlink_server_listen_address(c->varlink_server, "/run/systemd/io.systemd.Hostname", 0666);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind to Varlink socket: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
_cleanup_(context_destroy) Context context = {
|
||||
.hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
|
||||
@ -1630,6 +1728,10 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = connect_varlink(&context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_event_loop_with_idle(
|
||||
context.event,
|
||||
context.bus,
|
||||
|
@ -174,6 +174,7 @@ shared_sources = files(
|
||||
'varlink-idl.c',
|
||||
'varlink-io.systemd.c',
|
||||
'varlink-io.systemd.Credentials.c',
|
||||
'varlink-io.systemd.Hostname.c',
|
||||
'varlink-io.systemd.Journal.c',
|
||||
'varlink-io.systemd.ManagedOOM.c',
|
||||
'varlink-io.systemd.Network.c',
|
||||
|
36
src/shared/varlink-io.systemd.Hostname.c
Normal file
36
src/shared/varlink-io.systemd.Hostname.c
Normal file
@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "varlink-io.systemd.Credentials.h"
|
||||
|
||||
static VARLINK_DEFINE_METHOD(
|
||||
Describe,
|
||||
VARLINK_DEFINE_OUTPUT(Hostname, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(StaticHostname, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(PrettyHostname, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(DefaultHostname, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(HostnameSource, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(IconName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(Chassis, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(Deployment, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(Location, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(KernelName, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(KernelRelease, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(KernelVersion, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(OperatingSystemPrettyName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(OperatingSystemCPEName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(OperatingSystemHomeURL, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(OperatingSystemSupportEnd, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(HardwareVendor, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(HardwareModel, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(HardwareSerial, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(FirmwareVersion, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(FirmwareVendor, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(FirmwareDate, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(MachineID, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(BootID, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(ProductUUID, VARLINK_STRING, VARLINK_NULLABLE));
|
||||
|
||||
VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Hostname,
|
||||
"io.systemd.Hostname",
|
||||
&vl_method_Describe);
|
6
src/shared/varlink-io.systemd.Hostname.h
Normal file
6
src/shared/varlink-io.systemd.Hostname.h
Normal file
@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "varlink-idl.h"
|
||||
|
||||
extern const VarlinkInterface vl_interface_io_systemd_Hostname;
|
@ -228,6 +228,14 @@ testcase_nss-myhostname() {
|
||||
(! getent hosts -s myhostname fd00:dead:beef:cafe::1)
|
||||
}
|
||||
|
||||
test_varlink() {
|
||||
A="$(mktemp -u)"
|
||||
B="$(mktemp -u)"
|
||||
varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' --json=short > "$A"
|
||||
hostnamectl --json=short > "$B"
|
||||
cmp "$A" "$B"
|
||||
}
|
||||
|
||||
run_testcases
|
||||
|
||||
touch /testok
|
||||
|
@ -113,3 +113,7 @@ done
|
||||
(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord </dev/null)
|
||||
(! varlinkctl validate-idl "")
|
||||
(! varlinkctl validate-idl </dev/null)
|
||||
|
||||
varlinkctl info /run/systemd/io.systemd.Hostname
|
||||
varlinkctl introspect /run/systemd/io.systemd.Hostname io.systemd.Hostname
|
||||
varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}'
|
||||
|
@ -321,6 +321,11 @@ units = [
|
||||
'conditions' : ['ENABLE_HOSTNAMED'],
|
||||
'symlinks' : ['dbus-org.freedesktop.hostname1.service'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-hostnamed.socket',
|
||||
'conditions' : ['ENABLE_HOSTNAMED'],
|
||||
'symlinks' : ['sockets.target.wants/'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-hwdb-update.service.in',
|
||||
'conditions' : ['ENABLE_HWDB'],
|
||||
|
19
units/systemd-hostnamed.socket
Normal file
19
units/systemd-hostnamed.socket
Normal file
@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Hostname Service Varlink Socket
|
||||
Documentation=man:systemd-hostnamed.service(8)
|
||||
Documentation=man:hostname(5)
|
||||
Documentation=man:machine-info(5)
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.Hostname
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
Loading…
Reference in New Issue
Block a user