plugin.c revision ecd6cf800b63704be73fb264c3f5b6e0dafc068d
16185db8dougm/*
26185db8dougm * CDDL HEADER START
36185db8dougm *
46185db8dougm * The contents of this file are subject to the terms of the
56185db8dougm * Common Development and Distribution License (the "License").
66185db8dougm * You may not use this file except in compliance with the License.
76185db8dougm *
86185db8dougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96185db8dougm * or http://www.opensolaris.org/os/licensing.
106185db8dougm * See the License for the specific language governing permissions
116185db8dougm * and limitations under the License.
126185db8dougm *
136185db8dougm * When distributing Covered Code, include this CDDL HEADER in each
146185db8dougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156185db8dougm * If applicable, add the following below this CDDL HEADER, with the
166185db8dougm * fields enclosed by brackets "[]" replaced with your own identifying
176185db8dougm * information: Portions Copyright [yyyy] [name of copyright owner]
186185db8dougm *
196185db8dougm * CDDL HEADER END
206185db8dougm */
216185db8dougm
226185db8dougm/*
2324424a3dougm * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
246185db8dougm * Use is subject to license terms.
256185db8dougm */
266185db8dougm
276185db8dougm#pragma ident	"%Z%%M%	%I%	%E% SMI"
286185db8dougm
296185db8dougm#include <stdio.h>
306185db8dougm#include <stdlib.h>
316185db8dougm#include <string.h>
326185db8dougm#include <libshare.h>
336185db8dougm#include "libshare_impl.h"
346185db8dougm#include <dlfcn.h>
356185db8dougm#include <link.h>
366185db8dougm#include <sys/types.h>
376185db8dougm#include <sys/param.h>
386185db8dougm#include <sys/stat.h>
396185db8dougm#include <dirent.h>
406185db8dougm#include <libintl.h>
41549ec3fdougm#include <sys/systeminfo.h>
42549ec3fdougm
43549ec3fdougm#define	MAXISALEN	257	/* based on sysinfo(2) man page */
446185db8dougm
456185db8dougm/*
466185db8dougm * protocol plugin interface
476185db8dougm *
486185db8dougm * finds plugins and makes them accessible. This is only "used" by
496185db8dougm * libshare.so.
506185db8dougm */
516185db8dougm
526185db8dougmstruct sa_proto_plugin *sap_proto_list;
536185db8dougm
546185db8dougmstatic struct sa_proto_handle sa_proto_handle;
556185db8dougm
566185db8dougmvoid proto_plugin_fini();
576185db8dougm
586185db8dougm/*
596185db8dougm * proto_plugin_init()
606185db8dougm *
616185db8dougm * Initialize the protocol specific plugin modules.
626185db8dougm *
636185db8dougm * Walk /usr/lib/fs/\* for libshare_*.so modules. That is,
646185db8dougm * /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory
656185db8dougm * would have a modules with name libshare_<proto>.so. If one is
666185db8dougm * found, initialize it and add to the internal list of
676185db8dougm * protocols. These are used for protocol specifici operations.
686185db8dougm */
696185db8dougm
706185db8dougmint
716185db8dougmproto_plugin_init()
726185db8dougm{
736185db8dougm	struct sa_proto_plugin *proto;
746185db8dougm	int num_protos = 0;
756185db8dougm	int err;
766185db8dougm	struct sa_plugin_ops *plugin_ops;
776185db8dougm	void *dlhandle;
786185db8dougm	DIR *dir;
796185db8dougm	struct dirent *dent;
806185db8dougm	int ret = SA_OK;
816185db8dougm	struct stat st;
826185db8dougm
836185db8dougm	/*
846185db8dougm	 * should walk "/usr/lib/fs/" for files of the form:
856185db8dougm	 * libshare_*.so
866185db8dougm	 */
876185db8dougm	dir = opendir(SA_LIB_DIR);
886185db8dougm	if (dir != NULL) {
896185db8dougm	    while (ret == SA_OK && (dent = readdir(dir)) != NULL) {
906185db8dougm		char path[MAXPATHLEN];
91549ec3fdougm		char isa[MAXISALEN];
92549ec3fdougm
93549ec3fdougm#if defined(_LP64)
94549ec3fdougm		if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
95549ec3fdougm		    isa[0] = '\0';
96549ec3fdougm#else
97549ec3fdougm		isa[0] = '\0';
98549ec3fdougm#endif
996185db8dougm		(void) snprintf(path, MAXPATHLEN,
100549ec3fdougm				"%s/%s/%s/libshare_%s.so.1",
101549ec3fdougm				SA_LIB_DIR,
102549ec3fdougm				dent->d_name,
103549ec3fdougm				isa,
104549ec3fdougm				dent->d_name);
105549ec3fdougm			if (stat(path, &st) < 0) {
1066185db8dougm		    /* file doesn't exist, so don't try to map it */
1076185db8dougm		    continue;
1086185db8dougm		}
109549ec3fdougm		dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY);
1106185db8dougm		if (dlhandle != NULL) {
1116185db8dougm		    plugin_ops = (struct sa_plugin_ops *)
1126185db8dougm					dlsym(dlhandle,	"sa_plugin_ops");
1136185db8dougm		    proto = (struct sa_proto_plugin *)
1146185db8dougm			calloc(1, sizeof (struct sa_proto_plugin));
1156185db8dougm		    if (proto != NULL) {
1166185db8dougm			proto->plugin_ops = plugin_ops;
1176185db8dougm			proto->plugin_handle = dlhandle;
1186185db8dougm			num_protos++;
1196185db8dougm			proto->plugin_next = sap_proto_list;
1206185db8dougm			sap_proto_list = proto;
1216185db8dougm		    } else {
1226185db8dougm			ret = SA_NO_MEMORY;
1236185db8dougm		    }
1246185db8dougm		} else {
1256185db8dougm		    (void) fprintf(stderr,
12624424a3dougm			    dgettext(TEXT_DOMAIN,
12724424a3dougm				    "Error in plugin for protocol %s: %s\n"),
1286185db8dougm			    dent->d_name, dlerror());
1296185db8dougm		}
1306185db8dougm	    }
1316185db8dougm	    (void) closedir(dir);
1326185db8dougm	}
1336185db8dougm	if (ret == SA_OK) {
1346185db8dougm	    sa_proto_handle.sa_proto =
1356185db8dougm			(char **)calloc(num_protos, sizeof (char *));
1366185db8dougm	    sa_proto_handle.sa_ops =
1376185db8dougm			(struct sa_plugin_ops **)calloc(num_protos,
1386185db8dougm					    sizeof (struct sa_plugin_ops *));
1396185db8dougm	    if (sa_proto_handle.sa_proto != NULL &&
1406185db8dougm		sa_proto_handle.sa_ops != NULL) {
1416185db8dougm		int i;
1426185db8dougm		struct sa_proto_plugin *tmp;
1436185db8dougm		for (i = 0, tmp = sap_proto_list; i < num_protos;
1446185db8dougm		    tmp = tmp->plugin_next) {
1456185db8dougm		    err = 0;
1466185db8dougm		    if (tmp->plugin_ops->sa_init != NULL)
1476185db8dougm			err = tmp->plugin_ops->sa_init();
1486185db8dougm		    if (err == SA_OK) {
1496185db8dougm			/* only include if the init succeeded or was NULL */
1506185db8dougm			sa_proto_handle.sa_num_proto++;
1516185db8dougm			sa_proto_handle.sa_ops[i] = tmp->plugin_ops;
1526185db8dougm			sa_proto_handle.sa_proto[i] =
1536185db8dougm					tmp->plugin_ops->sa_protocol;
1546185db8dougm			i++;
1556185db8dougm		    }
1566185db8dougm		}
1576185db8dougm	    }
1586185db8dougm	} else {
1596185db8dougm	    /* there was an error, so cleanup prior to return of failure. */
1606185db8dougm	    proto_plugin_fini();
1616185db8dougm	}
1626185db8dougm	return (ret);
1636185db8dougm}
1646185db8dougm
1656185db8dougm/*
1666185db8dougm * proto_plugin_fini()
1676185db8dougm *
1686185db8dougm * uninitialize all the plugin modules.
1696185db8dougm */
1706185db8dougm
1716185db8dougmvoid
1726185db8dougmproto_plugin_fini()
1736185db8dougm{
1746185db8dougm	/*
1756185db8dougm	 * free up all the protocols, calling their fini, if there is
1766185db8dougm	 * one.
1776185db8dougm	 */
1786185db8dougm	while (sap_proto_list != NULL) {
1796185db8dougm	    struct sa_proto_plugin *next;
1806185db8dougm	    next = sap_proto_list->plugin_next;
1816185db8dougm	    sap_proto_list->plugin_ops->sa_fini();
1826185db8dougm	    if (sap_proto_list->plugin_handle != NULL)
1836185db8dougm		(void) dlclose(sap_proto_list->plugin_handle);
1846185db8dougm	    free(sap_proto_list);
1856185db8dougm	    sap_proto_list = next;
1866185db8dougm	}
1876185db8dougm	if (sa_proto_handle.sa_ops != NULL) {
1886185db8dougm	    free(sa_proto_handle.sa_ops);
1896185db8dougm	    sa_proto_handle.sa_ops = NULL;
1906185db8dougm	}
1916185db8dougm	if (sa_proto_handle.sa_proto != NULL) {
1926185db8dougm	    free(sa_proto_handle.sa_proto);
1936185db8dougm	    sa_proto_handle.sa_proto = NULL;
1946185db8dougm	}
1956185db8dougm	sa_proto_handle.sa_num_proto = 0;
1966185db8dougm}
1976185db8dougm
1986185db8dougm/*
1996185db8dougm * find_protocol(proto)
2006185db8dougm *
2016185db8dougm * Search the plugin list for the specified protocol and return the
2026185db8dougm * ops vector.  NULL if protocol is not defined.
2036185db8dougm */
2046185db8dougm
2056185db8dougmstatic struct sa_plugin_ops *
2066185db8dougmfind_protocol(char *proto)
2076185db8dougm{
2086185db8dougm	int i;
2096185db8dougm
2106185db8dougm	if (proto != NULL) {
2116185db8dougm	    for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
2126185db8dougm		if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0)
2136185db8dougm		    return (sa_proto_handle.sa_ops[i]);
2146185db8dougm	    }
2156185db8dougm	}
2166185db8dougm	return (NULL);
2176185db8dougm}
2186185db8dougm
2196185db8dougm/*
2206185db8dougm * sa_proto_share(proto, share)
2216185db8dougm *
2226185db8dougm * Activate a share for the specified protocol.
2236185db8dougm */
2246185db8dougm
2256185db8dougmint
2266185db8dougmsa_proto_share(char *proto, sa_share_t share)
2276185db8dougm{
2286185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
2296185db8dougm	int ret = SA_INVALID_PROTOCOL;
2306185db8dougm
2316185db8dougm	if (ops != NULL && ops->sa_share != NULL)
2326185db8dougm	    ret = ops->sa_share(share);
2336185db8dougm	return (ret);
2346185db8dougm}
2356185db8dougm
2366185db8dougm/*
2376185db8dougm * sa_proto_unshare(proto, path)
2386185db8dougm *
2396185db8dougm * Deactivate (unshare) the path for this protocol.
2406185db8dougm */
2416185db8dougm
2426185db8dougmint
243ecd6cf8markssa_proto_unshare(sa_share_t share, char *proto, char *path)
2446185db8dougm{
2456185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
2466185db8dougm	int ret = SA_INVALID_PROTOCOL;
2476185db8dougm
2486185db8dougm	if (ops != NULL && ops->sa_unshare != NULL)
249ecd6cf8marks	    ret = ops->sa_unshare(share, path);
2506185db8dougm	return (ret);
2516185db8dougm}
2526185db8dougm
2536185db8dougm/*
2546185db8dougm * sa_proto_valid_prop(proto, prop, opt)
2556185db8dougm *
2566185db8dougm * check to see if the specified prop is valid for this protocol.
2576185db8dougm */
2586185db8dougm
2596185db8dougmint
2606185db8dougmsa_proto_valid_prop(char *proto, sa_property_t prop, sa_optionset_t opt)
2616185db8dougm{
2626185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
2636185db8dougm	int ret = 0;
2646185db8dougm
2656185db8dougm	if (ops != NULL && ops->sa_valid_prop != NULL)
2666185db8dougm	    ret = ops->sa_valid_prop(prop, opt);
2676185db8dougm	return (ret);
2686185db8dougm}
2696185db8dougm
2706185db8dougm/*
2716185db8dougm * sa_proto_valid_space(proto, space)
2726185db8dougm *
2736185db8dougm * check if space is valid optionspace for proto.
2746185db8dougm * Protocols that don't implement this don't support spaces.
2756185db8dougm */
2766185db8dougmint
2776185db8dougmsa_proto_valid_space(char *proto, char *token)
2786185db8dougm{
2796185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
2806185db8dougm	int ret = 0;
2816185db8dougm
2826185db8dougm	if (ops != NULL && ops->sa_valid_space != NULL)
2836185db8dougm	    ret = ops->sa_valid_space(token);
2846185db8dougm	return (ret);
2856185db8dougm}
2866185db8dougm
2876185db8dougm/*
2886185db8dougm * sa_proto_space_alias(proto, space)
2896185db8dougm *
2906185db8dougm * if the name for space is an alias, return its proper name.  This is
2916185db8dougm * used to translate "default" values into proper form.
2926185db8dougm */
2936185db8dougmchar *
2946185db8dougmsa_proto_space_alias(char *proto, char *space)
2956185db8dougm{
2966185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
2976185db8dougm	char *ret = space;
2986185db8dougm
2996185db8dougm	if (ops != NULL && ops->sa_space_alias != NULL)
3006185db8dougm	    ret = ops->sa_space_alias(space);
3016185db8dougm	return (ret);
3026185db8dougm}
3036185db8dougm
3046185db8dougm/*
3056185db8dougm * sa_proto_security_prop(proto, token)
3066185db8dougm *
3076185db8dougm * Check to see if the property name in token is a valid named
3086185db8dougm * optionset property.
3096185db8dougm */
3106185db8dougm
3116185db8dougmint
3126185db8dougmsa_proto_security_prop(char *proto, char *token)
3136185db8dougm{
3146185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
3156185db8dougm	int ret = 0;
3166185db8dougm
3176185db8dougm	if (ops != NULL && ops->sa_security_prop != NULL)
3186185db8dougm	    ret = ops->sa_security_prop(token);
3196185db8dougm	return (ret);
3206185db8dougm}
3216185db8dougm
3226185db8dougm/*
3236185db8dougm * sa_proto_legacy_opts(proto, grouup, options)
3246185db8dougm *
3256185db8dougm * Have the protocol specific parser parse the options string and add
3266185db8dougm * an appropriate optionset to group.
3276185db8dougm */
3286185db8dougm
3296185db8dougmint
3306185db8dougmsa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
3316185db8dougm{
3326185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
3336185db8dougm	int ret = SA_INVALID_PROTOCOL;
3346185db8dougm
3356185db8dougm	if (ops != NULL && ops->sa_legacy_opts != NULL)
3366185db8dougm	    ret = ops->sa_legacy_opts(group, options);
3376185db8dougm	return (ret);
3386185db8dougm}
3396185db8dougm
3406185db8dougm/*
3416185db8dougm * sa_proto_legacy_format(proto, group, hier)
3426185db8dougm *
3436185db8dougm * Return a legacy format string representing either the group's
3446185db8dougm * properties or the groups hierarchical properties.
3456185db8dougm */
3466185db8dougm
3476185db8dougmchar *
3486185db8dougmsa_proto_legacy_format(char *proto, sa_group_t group, int hier)
3496185db8dougm{
3506185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
3516185db8dougm	char *ret = NULL;
3526185db8dougm
3536185db8dougm	if (ops != NULL && ops->sa_legacy_format != NULL)
3546185db8dougm	    ret = ops->sa_legacy_format(group, hier);
3556185db8dougm	return (ret);
3566185db8dougm}
3576185db8dougm
3586185db8dougmvoid
3596185db8dougmsa_format_free(char *str)
3606185db8dougm{
3616185db8dougm	free(str);
3626185db8dougm}
3636185db8dougm
3646185db8dougm/*
3656185db8dougm * sharectl related API functions
3666185db8dougm */
3676185db8dougm
3686185db8dougm/*
3696185db8dougm * sa_proto_get_properties(proto)
3706185db8dougm *
3716185db8dougm * Return the set of properties that are specific to the
3726185db8dougm * protocol. These are usually in /etc/dfs/<proto> and related files,
3736185db8dougm * but only the protocol module knows which ones for sure.
3746185db8dougm */
3756185db8dougm
3766185db8dougmsa_protocol_properties_t
3776185db8dougmsa_proto_get_properties(char *proto)
3786185db8dougm{
3796185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
3806185db8dougm	sa_protocol_properties_t props = NULL;
3816185db8dougm
3826185db8dougm	if (ops != NULL && ops->sa_get_proto_set != NULL)
3836185db8dougm	    props = ops->sa_get_proto_set();
3846185db8dougm	return (props);
3856185db8dougm}
3866185db8dougm
3876185db8dougm/*
3886185db8dougm * sa_proto_set_property(proto, prop)
3896185db8dougm *
3906185db8dougm * Update the protocol specifiec property.
3916185db8dougm */
3926185db8dougm
3936185db8dougmint
3946185db8dougmsa_proto_set_property(char *proto, sa_property_t prop)
3956185db8dougm{
3966185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
3976185db8dougm	int ret = SA_OK;
3986185db8dougm	if (ops != NULL && ops->sa_set_proto_prop != NULL)
3996185db8dougm	    ret = ops->sa_set_proto_prop(prop);
4006185db8dougm	return (ret);
4016185db8dougm}
4026185db8dougm
4036185db8dougm/*
4046185db8dougm * sa_valid_protocol(proto)
4056185db8dougm *
4066185db8dougm * check to see if the protocol specified is defined by a
4076185db8dougm * plugin. Returns true (1) or false (0)
4086185db8dougm */
4096185db8dougm
4106185db8dougmint
4116185db8dougmsa_valid_protocol(char *proto)
4126185db8dougm{
4136185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
4146185db8dougm	return (ops != NULL);
4156185db8dougm}
4166185db8dougm
4176185db8dougm/*
4186185db8dougm * Return the current operational status of the protocol
4196185db8dougm */
4206185db8dougm
4216185db8dougmchar *
4226185db8dougmsa_get_protocol_status(char *proto)
4236185db8dougm{
4246185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
4256185db8dougm	char *ret = NULL;
4266185db8dougm	if (ops != NULL && ops->sa_get_proto_status != NULL)
4276185db8dougm	    ret = ops->sa_get_proto_status(proto);
4286185db8dougm	return (ret);
4296185db8dougm}
4306185db8dougm
4316185db8dougm/*
4326185db8dougm * sa_proto_update_legacy(proto, share)
4336185db8dougm *
4346185db8dougm * Update the protocol specific legacy files if necessary for the
4356185db8dougm * specified share.
4366185db8dougm */
4376185db8dougm
4386185db8dougmint
4396185db8dougmsa_proto_update_legacy(char *proto, sa_share_t share)
4406185db8dougm{
4416185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
4426185db8dougm	int ret = SA_NOT_IMPLEMENTED;
4436185db8dougm
4446185db8dougm	if (ops != NULL) {
4456185db8dougm	    if (ops->sa_update_legacy != NULL)
4466185db8dougm		ret = ops->sa_update_legacy(share);
4476185db8dougm	}
4486185db8dougm	return (ret);
4496185db8dougm}
4506185db8dougm
4516185db8dougm/*
4526185db8dougm * sa_delete_legacy(proto, share)
4536185db8dougm *
4546185db8dougm * remove the specified share from the protocol specific legacy files.
4556185db8dougm */
4566185db8dougm
4576185db8dougmint
4586185db8dougmsa_proto_delete_legacy(char *proto, sa_share_t share)
4596185db8dougm{
4606185db8dougm	struct sa_plugin_ops *ops = find_protocol(proto);
4616185db8dougm	int ret = SA_OK;
4626185db8dougm
4636185db8dougm	if (ops != NULL) {
4646185db8dougm	    if (ops->sa_delete_legacy != NULL)
4656185db8dougm		ret = ops->sa_delete_legacy(share);
4666185db8dougm	} else {
4676185db8dougm	    if (proto != NULL)
4686185db8dougm		ret = SA_NOT_IMPLEMENTED;
4696185db8dougm	    else
4706185db8dougm		ret = SA_INVALID_PROTOCOL;
4716185db8dougm	}
4726185db8dougm	return (ret);
4736185db8dougm}
474