| /* GIO - GLib Input, Output and Streaming Library | |
| * | |
| * Copyright (C) 2006-2007 Red Hat, Inc. | |
| * | |
| * SPDX-License-Identifier: LGPL-2.1-or-later | |
| * | |
| * 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, see <http://www.gnu.org/licenses/>. | |
| * | |
| * Author: Alexander Larsson <alexl@redhat.com> | |
| */ | |
| #include "config.h" | |
| #include <gio/gio.h> | |
| #include "giomodule-priv.h" | |
| #include <gstdio.h> | |
| #include <errno.h> | |
| #include <locale.h> | |
| #include "glib/glib-private.h" | |
| static gboolean | |
| is_valid_module_name (const gchar *basename) | |
| { | |
| #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) | |
| #if defined(__APPLE__) | |
| return g_str_has_prefix (basename, "lib") && | |
| (g_str_has_suffix (basename, ".so") || | |
| g_str_has_suffix (basename, ".dylib")); | |
| #else | |
| return | |
| g_str_has_prefix (basename, "lib") && | |
| g_str_has_suffix (basename, ".so"); | |
| #endif | |
| #else | |
| return g_str_has_suffix (basename, ".dll"); | |
| #endif | |
| } | |
| static void | |
| query_dir (const char *dirname) | |
| { | |
| GString *data; | |
| GDir *dir; | |
| GList *list = NULL, *iterator = NULL; | |
| const char *name; | |
| char *cachename; | |
| char **(* query) (void); | |
| GError *error; | |
| int i; | |
| if (!g_module_supported ()) | |
| return; | |
| error = NULL; | |
| dir = g_dir_open (dirname, 0, &error); | |
| if (!dir) | |
| { | |
| g_printerr ("Unable to open directory %s: %s\n", dirname, error->message); | |
| g_error_free (error); | |
| return; | |
| } | |
| data = g_string_new (""); | |
| while ((name = g_dir_read_name (dir))) | |
| list = g_list_prepend (list, g_strdup (name)); | |
| list = g_list_sort (list, (GCompareFunc) g_strcmp0); | |
| for (iterator = list; iterator; iterator = iterator->next) | |
| { | |
| GModule *module; | |
| gchar *path; | |
| char **extension_points; | |
| name = iterator->data; | |
| if (!is_valid_module_name (name)) | |
| continue; | |
| path = g_build_filename (dirname, name, NULL); | |
| module = g_module_open_full (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL, &error); | |
| g_free (path); | |
| if (module) | |
| { | |
| gchar *modulename; | |
| gchar *symname; | |
| modulename = _g_io_module_extract_name (name); | |
| symname = g_strconcat ("g_io_", modulename, "_query", NULL); | |
| g_module_symbol (module, symname, (gpointer) &query); | |
| g_free (symname); | |
| g_free (modulename); | |
| if (!query) | |
| { | |
| /* Fallback to old name */ | |
| g_module_symbol (module, "g_io_module_query", (gpointer) &query); | |
| } | |
| if (query) | |
| { | |
| extension_points = query (); | |
| if (extension_points) | |
| { | |
| g_string_append_printf (data, "%s: ", name); | |
| for (i = 0; extension_points[i] != NULL; i++) | |
| g_string_append_printf (data, "%s%s", i == 0 ? "" : ",", extension_points[i]); | |
| g_string_append (data, "\n"); | |
| g_strfreev (extension_points); | |
| } | |
| } | |
| g_module_close (module); | |
| } | |
| else | |
| { | |
| g_debug ("Failed to open module %s: %s", name, error->message); | |
| } | |
| g_clear_error (&error); | |
| } | |
| g_dir_close (dir); | |
| g_list_free_full (list, g_free); | |
| cachename = g_build_filename (dirname, "giomodule.cache", NULL); | |
| if (data->len > 0) | |
| { | |
| error = NULL; | |
| if (!g_file_set_contents (cachename, data->str, data->len, &error)) | |
| { | |
| g_printerr ("Unable to create %s: %s\n", cachename, error->message); | |
| g_error_free (error); | |
| } | |
| } | |
| else | |
| { | |
| if (g_unlink (cachename) != 0 && errno != ENOENT) | |
| { | |
| int errsv = errno; | |
| g_printerr ("Unable to unlink %s: %s\n", cachename, g_strerror (errsv)); | |
| } | |
| } | |
| g_free (cachename); | |
| g_string_free (data, TRUE); | |
| } | |
| int | |
| main (gint argc, | |
| gchar *argv[]) | |
| { | |
| int i; | |
| if (argc <= 1) | |
| { | |
| g_print ("Usage: gio-querymodules <directory1> [<directory2> ...]\n"); | |
| g_print ("Will update giomodule.cache in the listed directories\n"); | |
| return 1; | |
| } | |
| setlocale (LC_ALL, GLIB_DEFAULT_LOCALE); | |
| /* Be defensive and ensure we're linked to GObject */ | |
| g_type_ensure (G_TYPE_OBJECT); | |
| for (i = 1; i < argc; i++) | |
| query_dir (argv[i]); | |
| return 0; | |
| } |