Then, use dlopen_many_sym_or_warn() with DLSYM_ARG() macro.
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)
#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"
#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"
#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;
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);
systemd_localed_sources = files(
'localed-util.c',
'localed.c',
+ 'xkbcommon-util.c',
)
localectl_sources = files('localectl.c')
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',
),
},
]
--- /dev/null
+/* 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
--- /dev/null
+/* 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