1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

Merge pull request #15624 from poettering/hostnamed-instant

hostnamed: stop caching so much
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-06-25 18:36:56 +02:00 committed by GitHub
commit 66ed28d332
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -28,6 +28,7 @@
#include "selinux-util.h"
#include "service-util.h"
#include "signal-util.h"
#include "stat-util.h"
#include "strv.h"
#include "user-util.h"
#include "util.h"
@ -36,54 +37,89 @@
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
enum {
PROP_HOSTNAME,
/* Read from /etc/hostname */
PROP_STATIC_HOSTNAME,
/* Read from /etc/machine-info */
PROP_PRETTY_HOSTNAME,
PROP_ICON_NAME,
PROP_CHASSIS,
PROP_DEPLOYMENT,
PROP_LOCATION,
/* Read from /etc/os-release (or /usr/lib/os-release) */
PROP_OS_PRETTY_NAME,
PROP_OS_CPE_NAME,
PROP_HOME_URL,
_PROP_MAX
PROP_OS_HOME_URL,
_PROP_MAX,
_PROP_INVALID = -1,
};
typedef struct Context {
char *data[_PROP_MAX];
struct stat etc_hostname_stat;
struct stat etc_os_release_stat;
struct stat etc_machine_info_stat;
Hashmap *polkit_registry;
} Context;
static void context_reset(Context *c) {
static void context_reset(Context *c, uint64_t mask) {
int p;
assert(c);
for (p = 0; p < _PROP_MAX; p++)
for (p = 0; p < _PROP_MAX; p++) {
if (!FLAGS_SET(mask, UINT64_C(1) << p))
continue;
c->data[p] = mfree(c->data[p]);
}
}
static void context_destroy(Context *c) {
assert(c);
context_reset(c);
context_reset(c, UINT64_MAX);
bus_verify_polkit_async_registry_free(c->polkit_registry);
}
static int context_read_data(Context *c) {
static void context_read_etc_hostname(Context *c) {
struct stat current_stat = {};
int r;
assert(c);
context_reset(c);
if (stat("/etc/hostname", &current_stat) >= 0 &&
stat_inode_unmodified(&c->etc_hostname_stat, &current_stat))
return;
c->data[PROP_HOSTNAME] = gethostname_malloc();
if (!c->data[PROP_HOSTNAME])
return -ENOMEM;
context_reset(c, UINT64_C(1) << PROP_STATIC_HOSTNAME);
r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
if (r < 0 && r != -ENOENT)
return r;
log_warning_errno(r, "Failed to read /etc/hostname, ignoring: %m");
c->etc_hostname_stat = current_stat;
}
static void context_read_machine_info(Context *c) {
struct stat current_stat = {};
int r;
assert(c);
if (stat("/etc/machine-info", &current_stat) >= 0 &&
stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat))
return;
context_reset(c,
(UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
(UINT64_C(1) << PROP_ICON_NAME) |
(UINT64_C(1) << PROP_CHASSIS) |
(UINT64_C(1) << PROP_DEPLOYMENT) |
(UINT64_C(1) << PROP_LOCATION));
r = parse_env_file(NULL, "/etc/machine-info",
"PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
@ -92,17 +128,36 @@ static int context_read_data(Context *c) {
"DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
"LOCATION", &c->data[PROP_LOCATION]);
if (r < 0 && r != -ENOENT)
return r;
log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
c->etc_machine_info_stat = current_stat;
}
static void context_read_os_release(Context *c) {
struct stat current_stat = {};
int r;
assert(c);
if ((stat("/etc/os-release", &current_stat) >= 0 ||
stat("/usr/lib/os-release", &current_stat) >= 0) &&
stat_inode_unmodified(&c->etc_os_release_stat, &current_stat))
return;
context_reset(c,
(UINT64_C(1) << PROP_OS_PRETTY_NAME) |
(UINT64_C(1) << PROP_OS_CPE_NAME) |
(UINT64_C(1) << PROP_OS_HOME_URL));
r = parse_os_release(NULL,
"PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
"HOME_URL", &c->data[PROP_HOME_URL],
"HOME_URL", &c->data[PROP_OS_HOME_URL],
NULL);
if (r < 0 && r != -ENOENT)
return r;
log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
return 0;
c->etc_os_release_stat = current_stat;
}
static bool valid_chassis(const char *chassis) {
@ -244,12 +299,22 @@ static bool hostname_is_useful(const char *hn) {
return !isempty(hn) && !is_localhost(hn);
}
static int context_update_kernel_hostname(Context *c) {
const char *static_hn;
const char *hn;
static int context_update_kernel_hostname(
Context *c,
const char *transient_hn) {
const char *static_hn, *hn;
struct utsname u;
assert(c);
if (!transient_hn) {
/* If no transient hostname is passed in, then let's check what is currently set. */
assert_se(uname(&u) >= 0);
transient_hn =
isempty(u.nodename) || streq(u.nodename, "(none)") ? NULL : u.nodename;
}
static_hn = c->data[PROP_STATIC_HOSTNAME];
/* /etc/hostname with something other than "localhost"
@ -258,8 +323,8 @@ static int context_update_kernel_hostname(Context *c) {
hn = static_hn;
/* ... the transient hostname, (ie: DHCP) comes next ... */
else if (!isempty(c->data[PROP_HOSTNAME]))
hn = c->data[PROP_HOSTNAME];
else if (!isempty(transient_hn))
hn = transient_hn;
/* ... fallback to static "localhost.*" ignored above ... */
else if (!isempty(static_hn))
@ -278,7 +343,6 @@ static int context_update_kernel_hostname(Context *c) {
}
static int context_write_data_static_hostname(Context *c) {
assert(c);
if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
@ -342,6 +406,94 @@ static int context_write_data_machine_info(Context *c) {
return write_env_file_label("/etc/machine-info", l);
}
static int property_get_hostname(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
_cleanup_free_ char *current = NULL;
int r;
r = gethostname_strict(&current);
if (r == -ENXIO)
return sd_bus_message_append(reply, "s", FALLBACK_HOSTNAME);
if (r < 0)
return r;
return sd_bus_message_append(reply, "s", current);
}
static int property_get_static_hostname(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Context *c = userdata;
assert(c);
context_read_etc_hostname(c);
return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
}
static int property_get_machine_info_field(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
sd_bus_slot *slot;
Context *c;
/* Acquire the context object without this property's userdata offset added. Explanation: we want
* access to two pointers here: a) the main context object we cache all properties in, and b) the
* pointer to the property field inside the context object that we are supposed to update and
* use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
* from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
* specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
* the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
* object is (which encapsulates the vtable registration), and then query the 'userdata' field
* directly off it. */
assert_se(slot = sd_bus_get_current_slot(bus));
assert_se(c = sd_bus_slot_get_userdata(slot));
context_read_machine_info(c);
return sd_bus_message_append(reply, "s", *(char**) userdata);
}
static int property_get_os_release_field(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
sd_bus_slot *slot;
Context *c;
/* As above, acquire the current context without this property's userdata offset added. */
assert_se(slot = sd_bus_get_current_slot(bus));
assert_se(c = sd_bus_slot_get_userdata(slot));
context_read_os_release(c);
return sd_bus_message_append(reply, "s", *(char**) userdata);
}
static int property_get_icon_name(
sd_bus *bus,
const char *path,
@ -355,6 +507,8 @@ static int property_get_icon_name(
Context *c = userdata;
const char *name;
context_read_machine_info(c);
if (isempty(c->data[PROP_ICON_NAME]))
name = n = context_fallback_icon_name(c);
else
@ -378,6 +532,8 @@ static int property_get_chassis(
Context *c = userdata;
const char *name;
context_read_machine_info(c);
if (isempty(c->data[PROP_CHASSIS]))
name = fallback_chassis();
else
@ -405,8 +561,8 @@ static int property_get_uname_field(
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *name;
int interactive;
int r;
int interactive, r;
struct utsname u;
assert(m);
assert(c);
@ -415,6 +571,8 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
if (r < 0)
return r;
context_read_etc_hostname(c);
if (isempty(name))
name = c->data[PROP_STATIC_HOSTNAME];
@ -424,7 +582,8 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
if (!hostname_is_valid(name, false))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
if (streq_ptr(name, c->data[PROP_HOSTNAME]))
assert_se(uname(&u) >= 0);
if (streq_ptr(name, u.nodename))
return sd_bus_reply_method_return(m, NULL);
r = bus_verify_polkit_async(
@ -441,17 +600,13 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = free_and_strdup(&c->data[PROP_HOSTNAME], name);
if (r < 0)
return r;
r = context_update_kernel_hostname(c);
r = context_update_kernel_hostname(c, name);
if (r < 0) {
log_error_errno(r, "Failed to set hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
}
log_info("Changed hostname to '%s'", strna(c->data[PROP_HOSTNAME]));
log_info("Changed hostname to '%s'", name);
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
@ -473,6 +628,8 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
name = empty_to_null(name);
context_read_etc_hostname(c);
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
@ -497,7 +654,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
if (r < 0)
return r;
r = context_update_kernel_hostname(c);
r = context_update_kernel_hostname(c, NULL);
if (r < 0) {
log_error_errno(r, "Failed to set hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
@ -530,6 +687,8 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess
name = empty_to_null(name);
context_read_machine_info(c);
if (streq_ptr(name, c->data[prop]))
return sd_bus_reply_method_return(m, NULL);
@ -671,19 +830,19 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Location", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD_WITH_NAMES("SetHostname",
"sb",
@ -826,10 +985,6 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
r = context_read_data(&context);
if (r < 0)
return log_error_errno(r, "Failed to read hostname and machine information: %m");
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");