diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c index 0e7c17f7..5dc37000 100644 --- a/libfprint/fp-context.c +++ b/libfprint/fp-context.c @@ -24,6 +24,11 @@ #include "fpi-device.h" #include +#include +#ifdef HAVE_LIBFPRINT_TOD +#include "tod/tod-shared-loader.h" +#endif + /** * SECTION: fp-context * @title: FpContext @@ -215,6 +220,8 @@ fp_context_finalize (GObject *object) g_object_run_dispose (G_OBJECT (priv->usb_ctx)); g_clear_object (&priv->usb_ctx); + fpi_tod_shared_drivers_unregister (); + G_OBJECT_CLASS (fp_context_parent_class)->finalize (object); } @@ -266,11 +273,16 @@ static void fp_context_init (FpContext *self) { g_autoptr(GError) error = NULL; + g_autoptr(GArray) shared_drivers = NULL; FpContextPrivate *priv = fp_context_get_instance_private (self); guint i; priv->drivers = fpi_get_driver_types (); + fpi_tod_shared_drivers_register (); + shared_drivers = fpi_tod_shared_drivers_get (); + g_array_prepend_vals (priv->drivers, shared_drivers->data, shared_drivers->len); + if (get_drivers_whitelist_env ()) { for (i = 0; i < priv->drivers->len;) diff --git a/libfprint/meson.build b/libfprint/meson.build index 50df8a0c..8cfef8c6 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -234,6 +234,10 @@ libfprint_private = static_library('fprint-private', link_with: libnbis, install: false) +if get_option('tod') + subdir('tod') +endif + libfprint_drivers = static_library('fprint-drivers', sources: drivers_sources, c_args: drivers_cflags, diff --git a/libfprint/tod/libfprint-tod.ver b/libfprint/tod/libfprint-tod.ver new file mode 100644 index 00000000..d18569f1 --- /dev/null +++ b/libfprint/tod/libfprint-tod.ver @@ -0,0 +1,6 @@ +LIBFPRINT_TOD_1.0.0 { +global: + fpi_*; +local: + *; +}; diff --git a/libfprint/tod/meson.build b/libfprint/tod/meson.build new file mode 100644 index 00000000..b864b598 --- /dev/null +++ b/libfprint/tod/meson.build @@ -0,0 +1,89 @@ +tod_soversion = 1 +tod_version = '@0@.0'.format(tod_soversion) +tod_versioned_path = '-'.join(tod_version.split('.')) +tod_subpath = meson.project_name() / 'tod-@0@'.format(tod_versioned_path) +tod_modules_prefix = get_option('libdir') / tod_subpath + +tod_conf = configuration_data() +tod_conf.set_quoted('TOD_DRIVERS_DIR', + get_option('prefix') / get_option('libdir') / tod_subpath) +configure_file(output: 'tod-config.h', configuration: tod_conf) + +gmodule_dep = dependency('gmodule-2.0', version: '>=' + glib_min_version) +deps += gmodule_dep + +mapfile = files('libfprint-tod.ver') + +libfprint_tod_private = static_library('fprint-tod-private', + sources: [ + 'tod-shared-loader.c', + ], + include_directories: include_directories('..'), + link_with: libfprint_private, + dependencies: deps, + install: false, +) + +tod_sources = [] +foreach source: libfprint_private_sources + tod_sources += '..' / source +endforeach + +libfprint_tod = library('fprint-tod', + sources: [ + tod_sources, + ], + soversion: (soversion * 100) + tod_soversion, + include_directories: include_directories('..'), + version: '@0@.'.format(soversion) + tod_version, + link_args: [ + '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]), + '-Wl,--unresolved-symbols=ignore-in-object-files' + ], + link_depends: mapfile, + link_with: [libfprint_private], + dependencies: deps, + install: true) + +deps += declare_dependency( + link_with: [ + libfprint_tod, + libfprint_tod_private, + ] +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(libfprint_tod, + name: 'libfprint-tod', + filebase: 'libfprint@0@-tod-@1@'.format(soversion, tod_versioned_path), + description: 'Private Libfprint Touch Drivers API', + version: meson.project_version() + '.@0@'.format(tod_version), + subdirs: tod_subpath, + requires_private: [ + meson.project_name() + '@0@'.format(soversion), + ], + variables: [ + 'tod_driversdir=${libdir}/@0@'.format(tod_subpath) + ] +) + +tod_headers = [] +extra_libfprint_headers = [ + 'drivers_api.h', +] + +foreach header: libfprint_private_headers + extra_libfprint_headers + tod_headers += '..' / header +endforeach + +custom_target('tod_fpi_enums_headers', + depends: fpi_enums, + input: fpi_enums_h, + output: 'fpi-enums.h', + command: ['cp', '@INPUT@', '-v', '@OUTPUT@'], + install: true, + install_dir: get_option('includedir') / tod_subpath) + +install_headers(tod_headers, + subdir: tod_subpath +) diff --git a/libfprint/tod/tod-shared-loader.c b/libfprint/tod/tod-shared-loader.c new file mode 100644 index 00000000..842e72dc --- /dev/null +++ b/libfprint/tod/tod-shared-loader.c @@ -0,0 +1,148 @@ +/* + * Shared library loader for libfprint + * Copyright (C) 2019 Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FP_COMPONENT "tod" + +#include + +#include "tod-shared-loader.h" +#include "fpi-device.h" +#include "fpi-log.h" +#include "tod-config.h" + +#define FPI_TOD_ENTRY_GTYPE_GETTER "fpi_tod_shared_driver_get_type" + +static GArray *shared_drivers = NULL; +static GList *shared_modules = NULL; + +typedef GModule FpiTodModule; +typedef GType (*FpiTodShardDriverTypeGetter) (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiTodModule, g_module_close); + +static const char * +get_tod_drivers_dir (void) +{ + const char *tod_env_path = g_getenv ("FP_TOD_DRIVERS_DIR"); + + if (!tod_env_path || *tod_env_path == '\0') + return TOD_DRIVERS_DIR; + + return tod_env_path; +} + +void +fpi_tod_shared_drivers_register (void) +{ + const char *dirname; + const char *basename; + + g_autoptr(GError) error = NULL; + g_autoptr(GDir) dir = NULL; + gpointer symbol; + + g_assert_null (shared_drivers); + + dirname = get_tod_drivers_dir (); + dir = g_dir_open (dirname, 0, &error); + + shared_drivers = g_array_new (TRUE, FALSE, sizeof (GType)); + + if (error) + { + fp_dbg ("Impossible to load the shared drivers dir %s", error->message); + return; + } + + while ((basename = g_dir_read_name (dir)) != NULL) + { + g_autoptr(FpiTodModule) module = NULL; + g_autoptr(GTypeClass) type_class = NULL; + g_autofree char *module_path = NULL; + FpiTodShardDriverTypeGetter type_getter; + FpDeviceClass *cls; + GType driver; + + if (!g_str_has_suffix (basename, ".so")) + continue; + + module_path = g_build_filename (dirname, basename, NULL); + + if (!g_file_test (module_path, G_FILE_TEST_IS_REGULAR)) + continue; + + fp_dbg ("Opening driver %s", module_path); + + module = g_module_open (module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + + if (!module) + { + fp_err ("Impossible to load module %s: %s", module_path, + g_module_error ()); + continue; + } + + if (!g_module_symbol (module, FPI_TOD_ENTRY_GTYPE_GETTER, &symbol)) + { + fp_err ("Library %s doesn't expose the required entry point symbol", + module_path); + continue; + } + + type_getter = symbol; + driver = type_getter (); + fp_dbg ("Found TOD entry point symbol %p, GType is %lu", symbol, driver); + + if (!G_TYPE_IS_OBJECT (driver) || !g_type_is_a (driver, FP_TYPE_DEVICE)) + { + fp_err ("Library %s returned GType (%lu) doesn't represent a device", + module_path, driver); + continue; + } + + type_class = g_type_class_ref (driver); + g_assert_true (g_type_check_class_is_a (type_class, FP_TYPE_DEVICE)); + + cls = FP_DEVICE_CLASS (type_class); + + fp_dbg ("Loading driver %s (%s)", cls->id, cls->full_name); + g_array_append_val (shared_drivers, driver); + + shared_modules = g_list_prepend (shared_modules, + g_steal_pointer (&module)); + } +} + +void +fpi_tod_shared_drivers_unregister (void) +{ + g_clear_pointer (&shared_drivers, g_array_unref); + + if (g_strcmp0 (g_getenv ("FP_TOD_KEEP_MODULES_OPEN"), "TRUE") != 0) + { + g_list_free_full (shared_modules, (GDestroyNotify) g_module_close); + shared_modules = NULL; + } +} + +GArray * +fpi_tod_shared_drivers_get (void) +{ + return g_array_ref (shared_drivers); +} diff --git a/libfprint/tod/tod-shared-loader.h b/libfprint/tod/tod-shared-loader.h new file mode 100644 index 00000000..8ed2e811 --- /dev/null +++ b/libfprint/tod/tod-shared-loader.h @@ -0,0 +1,28 @@ +/* + * Shared library loader for libfprint + * Copyright (C) 2019 Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include + + +void fpi_tod_shared_drivers_register (void); +void fpi_tod_shared_drivers_unregister (void); + +GArray *fpi_tod_shared_drivers_get (void); diff --git a/meson.build b/meson.build index c42cf2d6..2612ed52 100644 --- a/meson.build +++ b/meson.build @@ -187,6 +187,8 @@ if get_option('gtk-examples') endif endif +libfprint_conf.set10('HAVE_LIBFPRINT_TOD', get_option('tod')) + configure_file(output: 'config.h', configuration: libfprint_conf) subdir('libfprint') diff --git a/meson_options.txt b/meson_options.txt index 746efdc7..d059ae59 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -22,3 +22,8 @@ option('doc', description: 'Whether to build the API documentation', type: 'boolean', value: true) + +option('tod', + description: 'Whether to build the TOD library', + type: 'boolean', + value: true)