2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/param.h>
2N/A#include <dlfcn.h>
2N/A#include <link.h>
2N/A#include <dirent.h>
2N/A#include <libintl.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <synch.h>
2N/A#include <string.h>
2N/A#include <dirent.h>
2N/A#include <sys/stat.h>
2N/A#include <atomic.h>
2N/A
2N/A#include "libshare.h"
2N/A#include "libshare_impl.h"
2N/A
2N/Astatic sa_plugin_t *sa_fs_list;
2N/Astatic rwlock_t sa_fs_lock;
2N/A
2N/Astatic sa_plugin_t *sa_proto_list;
2N/Astatic rwlock_t sa_proto_lock;
2N/A
2N/Astatic sa_plugin_t *sa_cache_list;
2N/Astatic rwlock_t sa_cache_lock;
2N/A
2N/Astatic uint32_t sa_plugins_loaded; /* mask of plugins that have been loaded */
2N/Astatic mutex_t sa_plugins_lock;
2N/A
2N/A/*
2N/A * load_and_check(path, libname, type)
2N/A *
2N/A * dlopen the library and check to see if a valid libshare v2
2N/A * library of the correct type. If it is, load it and link it together
2N/A * as appropriate.
2N/A *
2N/A * The pi_init() routine is also called to give the plugin a chance
2N/A * to do any required initialization.
2N/A */
2N/Astatic void
2N/Aload_and_check(char *path, sa_plugin_type_t type)
2N/A{
2N/A int rc = SA_OK;
2N/A sa_plugin_t *plugin;
2N/A sa_plugin_t **pi_list;
2N/A rwlock_t *pi_lock;
2N/A sa_plugin_ops_t *pi_ops;
2N/A void *dlhandle;
2N/A
2N/A if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL) {
2N/A salog_error(0, "Error loading libshare plugin: %s: %s",
2N/A path, dlerror());
2N/A return;
2N/A }
2N/A
2N/A pi_ops = (sa_plugin_ops_t *)dlsym(dlhandle, "sa_plugin_ops");
2N/A if (pi_ops == NULL) {
2N/A salog_error(0, "Error loading libshare plugin: %s: %s",
2N/A path, dlerror());
2N/A (void) dlclose(dlhandle);
2N/A return;
2N/A }
2N/A
2N/A if (pi_ops->pi_ptype != type) {
2N/A salog_error(SA_INVALID_PLUGIN_TYPE,
2N/A "Error loading libshare plugin: %s", path);
2N/A (void) dlclose(dlhandle);
2N/A return;
2N/A }
2N/A
2N/A plugin = (sa_plugin_t *)calloc(1, sizeof (sa_plugin_t));
2N/A
2N/A if (plugin == NULL) {
2N/A (void) dlclose(dlhandle);
2N/A salog_error(SA_NO_MEMORY,
2N/A "Error loading libshare plugin: %s", path);
2N/A return;
2N/A }
2N/A
2N/A switch (type) {
2N/A case SA_PLUGIN_FS:
2N/A pi_lock = &sa_fs_lock;
2N/A pi_list = &sa_fs_list;
2N/A break;
2N/A case SA_PLUGIN_PROTO:
2N/A pi_lock = &sa_proto_lock;
2N/A pi_list = &sa_proto_list;
2N/A break;
2N/A case SA_PLUGIN_CACHE:
2N/A pi_lock = &sa_cache_lock;
2N/A pi_list = &sa_cache_list;
2N/A break;
2N/A default:
2N/A salog_error(SA_INVALID_PLUGIN_TYPE,
2N/A "Error loading libshare plugin: %s", path);
2N/A (void) dlclose(dlhandle);
2N/A free(plugin);
2N/A return;
2N/A }
2N/A
2N/A if ((pi_ops->pi_init != NULL) &&
2N/A ((rc = pi_ops->pi_init()) != SA_OK)) {
2N/A salog_error(rc,
2N/A "Error initializing libshare plugin: %s", path);
2N/A (void) dlclose(dlhandle);
2N/A free(plugin);
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * add plugin to list
2N/A */
2N/A (void) rw_wrlock(pi_lock);
2N/A plugin->pi_next = *pi_list;
2N/A plugin->pi_ops = pi_ops;
2N/A plugin->pi_hdl = dlhandle;
2N/A *pi_list = plugin;
2N/A (void) rw_unlock(pi_lock);
2N/A}
2N/A
2N/A/*
2N/A * plugin_load(type)
2N/A *
2N/A * find (and load) all modules of given type
2N/A */
2N/Astatic void
2N/Asaplugin_load(sa_plugin_type_t type)
2N/A{
2N/A DIR *dirp;
2N/A struct dirent64 *dp;
2N/A char *root;
2N/A char plugin_root[MAXPATHLEN];
2N/A char plugin_file[MAXPATHLEN];
2N/A#if defined(_LP64)
2N/A char isa[MAXISALEN];
2N/A#endif
2N/A
2N/A (void) mutex_lock(&sa_plugins_lock);
2N/A if (sa_plugins_loaded & (1 << type))
2N/A goto unlock_and_return;
2N/A
2N/A switch (type) {
2N/A case SA_PLUGIN_FS:
2N/A root = SA_PLUGIN_ROOT_FS;
2N/A break;
2N/A case SA_PLUGIN_PROTO:
2N/A root = SA_PLUGIN_ROOT_PROTO;
2N/A break;
2N/A case SA_PLUGIN_CACHE:
2N/A root = SA_PLUGIN_ROOT_CACHE;
2N/A break;
2N/A default:
2N/A goto unlock_and_return;
2N/A }
2N/A
2N/A#if defined(_LP64)
2N/A if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
2N/A isa[0] = '\0';
2N/A (void) snprintf(plugin_root, sizeof (plugin_root), "%s/%s", root, isa);
2N/A#else
2N/A (void) strlcpy(plugin_root, root, sizeof (plugin_root));
2N/A#endif
2N/A dirp = opendir(plugin_root);
2N/A if (dirp == NULL) {
2N/A salog_debug(SA_NO_PLUGIN_DIR,
2N/A "saplugin_load: %s", root);
2N/A goto unlock_and_return;
2N/A }
2N/A
2N/A while ((dp = readdir64(dirp)) != NULL) {
2N/A if (strncmp(dp->d_name, PLUGIN_LIB_PREFIX,
2N/A sizeof (PLUGIN_LIB_PREFIX) - 1) == 0) {
2N/A if (strlen(plugin_root) +
2N/A strlen(dp->d_name) + 1 > MAXPATHLEN) {
2N/A salog_error(SA_INVALID_PLUGIN_NAME,
2N/A "Error loading libshare plugin %s/%s",
2N/A plugin_root, dp->d_name);
2N/A continue;
2N/A }
2N/A (void) snprintf(plugin_file, sizeof (plugin_file),
2N/A "%s/%s", plugin_root, dp->d_name);
2N/A (void) load_and_check(plugin_file, type);
2N/A }
2N/A }
2N/A (void) closedir(dirp);
2N/A
2N/A /*
2N/A * mark plugin type as loaded regardless of success.
2N/A * This will prevent continuous attempts to load
2N/A * bad or non-existent plugins.
2N/A */
2N/A sa_plugins_loaded |= (1 << type);
2N/A
2N/Aunlock_and_return:
2N/A (void) mutex_unlock(&sa_plugins_lock);
2N/A}
2N/A
2N/A/*
2N/A * saplugin_unload
2N/A *
2N/A * Unload all plugin modules of the given type.
2N/A */
2N/Astatic void
2N/Asaplugin_unload(sa_plugin_type_t pi_type)
2N/A{
2N/A rwlock_t *pi_lock;
2N/A sa_plugin_t **pi_list;
2N/A sa_plugin_t *plugin, *next; /* use fs_plugin as generic type */
2N/A
2N/A (void) mutex_lock(&sa_plugins_lock);
2N/A if (!(sa_plugins_loaded & (1 << pi_type)))
2N/A goto unlock_and_return;
2N/A
2N/A switch (pi_type) {
2N/A case SA_PLUGIN_FS:
2N/A pi_lock = &sa_fs_lock;
2N/A pi_list = &sa_fs_list;
2N/A break;
2N/A
2N/A case SA_PLUGIN_PROTO:
2N/A pi_lock = &sa_proto_lock;
2N/A pi_list = &sa_proto_list;
2N/A break;
2N/A
2N/A case SA_PLUGIN_CACHE:
2N/A pi_lock = &sa_cache_lock;
2N/A pi_list = &sa_cache_list;
2N/A break;
2N/A default:
2N/A goto unlock_and_return;
2N/A }
2N/A
2N/A (void) rw_wrlock(pi_lock);
2N/A plugin = *pi_list;
2N/A while (plugin != NULL) {
2N/A next = plugin->pi_next;
2N/A /*
2N/A * call pi_fini() routine to give
2N/A * plugin a chance to cleanup.
2N/A */
2N/A if (plugin->pi_ops->pi_fini != NULL)
2N/A (void) plugin->pi_ops->pi_fini();
2N/A
2N/A if (plugin->pi_hdl != NULL) {
2N/A (void) dlclose(plugin->pi_hdl);
2N/A }
2N/A
2N/A free(plugin);
2N/A plugin = next;
2N/A }
2N/A (void) rw_unlock(pi_lock);
2N/A
2N/A sa_plugins_loaded &= ~(1 << pi_type);
2N/A
2N/Aunlock_and_return:
2N/A (void) mutex_unlock(&sa_plugins_lock);
2N/A}
2N/A
2N/A/*
2N/A * saplugin_unload_all
2N/A *
2N/A * Unload all loaded plugin modules.
2N/A * Called from _sa_fini() when libshare.so is unloaded.
2N/A */
2N/Avoid
2N/Asaplugin_unload_all(void)
2N/A{
2N/A saplugin_unload(SA_PLUGIN_FS);
2N/A saplugin_unload(SA_PLUGIN_PROTO);
2N/A saplugin_unload(SA_PLUGIN_CACHE);
2N/A}
2N/A
2N/A/*
2N/A * saplugin_find_ops
2N/A *
2N/A * return ops table for specified plugin
2N/A */
2N/Asa_plugin_ops_t *
2N/Asaplugin_find_ops(sa_plugin_type_t type, uint32_t ops_type)
2N/A{
2N/A sa_plugin_t *plugin;
2N/A sa_plugin_t **pi_list;
2N/A rwlock_t *pi_lock;
2N/A
2N/A /*
2N/A * load the plugin if not yet loaded
2N/A */
2N/A saplugin_load(type);
2N/A
2N/A switch (type) {
2N/A case SA_PLUGIN_FS:
2N/A pi_lock = &sa_fs_lock;
2N/A pi_list = &sa_fs_list;
2N/A break;
2N/A case SA_PLUGIN_PROTO:
2N/A pi_lock = &sa_proto_lock;
2N/A pi_list = &sa_proto_list;
2N/A break;
2N/A case SA_PLUGIN_CACHE:
2N/A pi_lock = &sa_cache_lock;
2N/A pi_list = &sa_cache_list;
2N/A break;
2N/A default:
2N/A return (NULL);
2N/A }
2N/A
2N/A (void) rw_rdlock(pi_lock);
2N/A for (plugin = *pi_list; plugin != NULL; plugin = plugin->pi_next) {
2N/A if (plugin->pi_ops != NULL &&
2N/A plugin->pi_ops->pi_type == ops_type)
2N/A break;
2N/A }
2N/A (void) rw_unlock(pi_lock);
2N/A
2N/A if (plugin != NULL)
2N/A return (plugin->pi_ops);
2N/A else
2N/A return (NULL);
2N/A}
2N/A
2N/Aint
2N/Asaplugin_get_protos(sa_proto_t **protos)
2N/A{
2N/A int i;
2N/A int plugin_cnt = 0;
2N/A sa_plugin_t *plugin;
2N/A
2N/A if (protos == NULL)
2N/A return (0);
2N/A
2N/A saplugin_load(SA_PLUGIN_PROTO);
2N/A
2N/A (void) rw_rdlock(&sa_proto_lock);
2N/A for (plugin = sa_proto_list; plugin != NULL; plugin = plugin->pi_next) {
2N/A if (plugin->pi_ops != NULL)
2N/A plugin_cnt++;
2N/A }
2N/A
2N/A *protos = calloc(plugin_cnt, sizeof (sa_proto_t));
2N/A if (*protos == NULL) {
2N/A (void) rw_unlock(&sa_proto_lock);
2N/A return (0);
2N/A }
2N/A
2N/A for (i = 0, plugin = sa_proto_list;
2N/A plugin != NULL;
2N/A ++i, plugin = plugin->pi_next) {
2N/A if (plugin->pi_ops != NULL)
2N/A (*protos)[i] = plugin->pi_ops->pi_type;
2N/A }
2N/A
2N/A (void) rw_unlock(&sa_proto_lock);
2N/A
2N/A return (plugin_cnt);
2N/A}
2N/A
2N/A/*
2N/A * saplugin_next_ops
2N/A *
2N/A * Return pointer to next plugin in the list of type specified
2N/A * If ops == NULL return first plugin in the list.
2N/A */
2N/Asa_plugin_ops_t *
2N/Asaplugin_next_ops(sa_plugin_type_t type, sa_plugin_ops_t *ops)
2N/A{
2N/A sa_plugin_t **pi_list;
2N/A rwlock_t *pi_lock;
2N/A sa_plugin_t *plugin;
2N/A
2N/A /*
2N/A * load the plugin if not yet loaded
2N/A */
2N/A saplugin_load(type);
2N/A
2N/A switch (type) {
2N/A case SA_PLUGIN_FS:
2N/A pi_lock = &sa_fs_lock;
2N/A pi_list = &sa_fs_list;
2N/A break;
2N/A case SA_PLUGIN_PROTO:
2N/A pi_lock = &sa_proto_lock;
2N/A pi_list = &sa_proto_list;
2N/A break;
2N/A case SA_PLUGIN_CACHE:
2N/A pi_lock = &sa_cache_lock;
2N/A pi_list = &sa_cache_list;
2N/A break;
2N/A default:
2N/A return (NULL);
2N/A }
2N/A
2N/A (void) rw_rdlock(pi_lock);
2N/A if (ops == NULL) {
2N/A plugin = *pi_list;
2N/A } else {
2N/A for (plugin = *pi_list; plugin != NULL;
2N/A plugin = plugin->pi_next) {
2N/A if (plugin->pi_ops == ops) {
2N/A plugin = plugin->pi_next;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A (void) rw_unlock(pi_lock);
2N/A
2N/A if (plugin != NULL)
2N/A return (plugin->pi_ops);
2N/A else
2N/A return (NULL);
2N/A}