summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2023-02-02 02:47:47 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2023-03-25 15:27:23 +0900
commitd45cbc071144c5003d2dc35d388790dacad6e6f0 (patch)
tree85760269b9053dfedef9bc6ea230f31f2cb5f953
parent384f22e39f563d15e5902ec23a342ef52d044169 (diff)
downloadsystemd-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.build16
-rw-r--r--src/locale/localed.c108
-rw-r--r--src/locale/meson.build11
-rw-r--r--src/locale/xkbcommon-util.c80
-rw-r--r--src/locale/xkbcommon-util.h30
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