diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-02-02 02:47:47 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-03-25 15:27:23 +0900 |
commit | d45cbc071144c5003d2dc35d388790dacad6e6f0 (patch) | |
tree | 85760269b9053dfedef9bc6ea230f31f2cb5f953 | |
parent | 384f22e39f563d15e5902ec23a342ef52d044169 (diff) | |
download | systemd-d45cbc071144c5003d2dc35d388790dacad6e6f0.tar.gz |
locale: split out xkbcommon related functions to xkbcommon-util.c
Then, use dlopen_many_sym_or_warn() with DLSYM_ARG() macro.
-rw-r--r-- | meson.build | 16 | ||||
-rw-r--r-- | src/locale/localed.c | 108 | ||||
-rw-r--r-- | src/locale/meson.build | 11 | ||||
-rw-r--r-- | src/locale/xkbcommon-util.c | 80 | ||||
-rw-r--r-- | src/locale/xkbcommon-util.h | 30 |
5 files changed, 125 insertions, 120 deletions
diff --git a/meson.build b/meson.build index 6770deed4f..b624c6d8f0 100644 --- a/meson.build +++ b/meson.build @@ -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) diff --git a/src/locale/localed.c b/src/locale/localed.c index e6e239d9bd..587e072c6b 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -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); diff --git a/src/locale/meson.build b/src/locale/meson.build index 60d2666ffd..98a0b44d63 100644 --- a/src/locale/meson.build +++ b/src/locale/meson.build @@ -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', ), }, ] diff --git a/src/locale/xkbcommon-util.c b/src/locale/xkbcommon-util.c new file mode 100644 index 0000000000..295ac8af8d --- /dev/null +++ b/src/locale/xkbcommon-util.c @@ -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 diff --git a/src/locale/xkbcommon-util.h b/src/locale/xkbcommon-util.h new file mode 100644 index 0000000000..e99c2d7783 --- /dev/null +++ b/src/locale/xkbcommon-util.h @@ -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 |