locale: split out xkbcommon related functions to xkbcommon-util.c

Then, use dlopen_many_sym_or_warn() with DLSYM_ARG() macro.
This commit is contained in:
Yu Watanabe 2023-02-02 02:47:47 +09:00
parent 384f22e39f
commit d45cbc0711
5 changed files with 125 additions and 120 deletions

View file

@ -3181,24 +3181,14 @@ if conf.get('ENABLE_HOSTNAMED') == 1
endif
if conf.get('ENABLE_LOCALED') == 1
if conf.get('HAVE_XKBCOMMON') == 1
# logind will load libxkbcommon.so dynamically on its own, but we still
# need to specify where the headers are
deps = [libdl,
libxkbcommon.partial_dependency(compile_args: true),
userspace,
versiondep]
else
deps = [userspace,
versiondep]
endif
dbus_programs += executable(
'systemd-localed',
systemd_localed_sources,
include_directories : includes,
link_with : [libshared],
dependencies : deps,
dependencies : libxkbcommon_deps +
[userspace,
versiondep],
install_rpath : rootpkglibdir,
install : true,
install_dir : rootlibexecdir)

View file

@ -5,11 +5,6 @@
#include <sys/types.h>
#include <unistd.h>
#if HAVE_XKBCOMMON
#include <xkbcommon/xkbcommon.h>
#include <dlfcn.h>
#endif
#include "sd-bus.h"
#include "alloc-util.h"
@ -19,7 +14,6 @@
#include "bus-message.h"
#include "bus-polkit.h"
#include "constants.h"
#include "dlfcn-util.h"
#include "kbd-util.h"
#include "localed-util.h"
#include "macro.h"
@ -32,6 +26,7 @@
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
#include "xkbcommon-util.h"
static int reload_system_manager(sd_bus *bus) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
@ -482,107 +477,6 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
return sd_bus_reply_method_return(m, NULL);
}
#if HAVE_XKBCOMMON
_printf_(3, 0)
static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
const char *fmt;
fmt = strjoina("libxkbcommon: ", format);
DISABLE_WARNING_FORMAT_NONLITERAL;
log_internalv(LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__, fmt, args);
REENABLE_WARNING;
}
#define LOAD_SYMBOL(symbol, dl, name) \
({ \
(symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \
(symbol) ? 0 : -EOPNOTSUPP; \
})
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
/* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge
* after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function
* pointers to the shared library are below: */
struct xkb_context* (*symbol_xkb_context_new)(enum xkb_context_flags flags) = NULL;
void (*symbol_xkb_context_unref)(struct xkb_context *context) = NULL;
void (*symbol_xkb_context_set_log_fn)(struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args)) = NULL;
struct xkb_keymap* (*symbol_xkb_keymap_new_from_names)(struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags) = NULL;
void (*symbol_xkb_keymap_unref)(struct xkb_keymap *keymap) = NULL;
const struct xkb_rule_names rmlvo = {
.model = model,
.layout = layout,
.variant = variant,
.options = options,
};
struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL;
_cleanup_(dlclosep) void *dl = NULL;
int r;
/* Compile keymap from RMLVO information to check out its validity */
dl = dlopen("libxkbcommon.so.0", RTLD_LAZY);
if (!dl)
return -EOPNOTSUPP;
r = LOAD_SYMBOL(symbol_xkb_context_new, dl, "xkb_context_new");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_context_unref, dl, "xkb_context_unref");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_context_set_log_fn, dl, "xkb_context_set_log_fn");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_keymap_new_from_names, dl, "xkb_keymap_new_from_names");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_keymap_unref, dl, "xkb_keymap_unref");
if (r < 0)
goto finish;
ctx = symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
if (!ctx) {
r = -ENOMEM;
goto finish;
}
symbol_xkb_context_set_log_fn(ctx, log_xkb);
km = symbol_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!km) {
r = -EINVAL;
goto finish;
}
r = 0;
finish:
if (symbol_xkb_keymap_unref && km)
symbol_xkb_keymap_unref(km);
if (symbol_xkb_context_unref && ctx)
symbol_xkb_context_unref(ctx);
return r;
}
#else
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
return 0;
}
#endif
static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(vc_context_clear) VCContext converted = {};
Context *c = ASSERT_PTR(userdata);

View file

@ -3,6 +3,7 @@
systemd_localed_sources = files(
'localed-util.c',
'localed.c',
'xkbcommon-util.c',
)
localectl_sources = files('localectl.c')
@ -28,11 +29,21 @@ if conf.get('ENABLE_LOCALED') == 1
install_dir : pkgdatadir)
endif
# logind will load libxkbcommon.so dynamically on its own, but we still need to
# specify where the headers are.
if conf.get('HAVE_XKBCOMMON') == 1
libxkbcommon_deps = [libdl,
libxkbcommon.partial_dependency(compile_args: true)]
else
libxkbcommon_deps = []
endif
tests += [
{
'sources' : files(
'test-localed-util.c',
'localed-util.c',
'xkbcommon-util.c',
),
},
]

View file

@ -0,0 +1,80 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "dlfcn-util.h"
#include "log.h"
#include "macro.h"
#include "string-util.h"
#include "xkbcommon-util.h"
#if HAVE_XKBCOMMON
static void *xkbcommon_dl = NULL;
struct xkb_context* (*sym_xkb_context_new)(enum xkb_context_flags flags);
void (*sym_xkb_context_unref)(struct xkb_context *context);
void (*sym_xkb_context_set_log_fn)(
struct xkb_context *context,
void (*log_fn)(
struct xkb_context *context,
enum xkb_log_level level,
const char *format,
va_list args));
struct xkb_keymap* (*sym_xkb_keymap_new_from_names)(
struct xkb_context *context,
const struct xkb_rule_names *names,
enum xkb_keymap_compile_flags flags);
void (*sym_xkb_keymap_unref)(struct xkb_keymap *keymap);
static int dlopen_xkbcommon(void) {
return dlopen_many_sym_or_warn(
&xkbcommon_dl, "libxkbcommon.so.0", LOG_DEBUG,
DLSYM_ARG(xkb_context_new),
DLSYM_ARG(xkb_context_unref),
DLSYM_ARG(xkb_context_set_log_fn),
DLSYM_ARG(xkb_keymap_new_from_names),
DLSYM_ARG(xkb_keymap_unref));
}
_printf_(3, 0)
static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
const char *fmt;
fmt = strjoina("libxkbcommon: ", format);
DISABLE_WARNING_FORMAT_NONLITERAL;
log_internalv(LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__, fmt, args);
REENABLE_WARNING;
}
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct xkb_context *, sym_xkb_context_unref, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct xkb_keymap *, sym_xkb_keymap_unref, NULL);
int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
_cleanup_(sym_xkb_context_unrefp) struct xkb_context *ctx = NULL;
_cleanup_(sym_xkb_keymap_unrefp) struct xkb_keymap *km = NULL;
const struct xkb_rule_names rmlvo = {
.model = model,
.layout = layout,
.variant = variant,
.options = options,
};
int r;
/* Compile keymap from RMLVO information to check out its validity */
r = dlopen_xkbcommon();
if (r < 0)
return r;
ctx = sym_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
if (!ctx)
return -ENOMEM;
sym_xkb_context_set_log_fn(ctx, log_xkb);
km = sym_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!km)
return -EINVAL;
return 0;
}
#endif

View file

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#if HAVE_XKBCOMMON
#include <xkbcommon/xkbcommon.h>
extern struct xkb_context* (*sym_xkb_context_new)(enum xkb_context_flags flags);
extern void (*sym_xkb_context_unref)(struct xkb_context *context);
extern void (*sym_xkb_context_set_log_fn)(
struct xkb_context *context,
void (*log_fn)(
struct xkb_context *context,
enum xkb_log_level level,
const char *format,
va_list args));
extern struct xkb_keymap* (*sym_xkb_keymap_new_from_names)(
struct xkb_context *context,
const struct xkb_rule_names *names,
enum xkb_keymap_compile_flags flags);
extern void (*sym_xkb_keymap_unref)(struct xkb_keymap *keymap);
int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options);
#else
static inline int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
return 0;
}
#endif