13034Sdougm /*
23034Sdougm  * CDDL HEADER START
33034Sdougm  *
43034Sdougm  * The contents of this file are subject to the terms of the
53034Sdougm  * Common Development and Distribution License (the "License").
63034Sdougm  * You may not use this file except in compliance with the License.
73034Sdougm  *
83034Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm  * or http://www.opensolaris.org/os/licensing.
103034Sdougm  * See the License for the specific language governing permissions
113034Sdougm  * and limitations under the License.
123034Sdougm  *
133034Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm  * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm  *
193034Sdougm  * CDDL HEADER END
203034Sdougm  */
213034Sdougm 
223034Sdougm /*
233407Sdougm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
243034Sdougm  * Use is subject to license terms.
253034Sdougm  */
263034Sdougm 
273034Sdougm #pragma ident	"%Z%%M%	%I%	%E% SMI"
283034Sdougm 
293034Sdougm #include <stdio.h>
303034Sdougm #include <stdlib.h>
313034Sdougm #include <string.h>
323034Sdougm #include <libshare.h>
333034Sdougm #include "libshare_impl.h"
343034Sdougm #include <dlfcn.h>
353034Sdougm #include <link.h>
363034Sdougm #include <sys/types.h>
373034Sdougm #include <sys/param.h>
383034Sdougm #include <sys/stat.h>
393034Sdougm #include <dirent.h>
403034Sdougm #include <libintl.h>
413910Sdougm #include <sys/systeminfo.h>
423910Sdougm 
433910Sdougm #define	MAXISALEN	257	/* based on sysinfo(2) man page */
443034Sdougm 
453034Sdougm /*
463034Sdougm  * protocol plugin interface
473034Sdougm  *
483034Sdougm  * finds plugins and makes them accessible. This is only "used" by
493034Sdougm  * libshare.so.
503034Sdougm  */
513034Sdougm 
523034Sdougm struct sa_proto_plugin *sap_proto_list;
533034Sdougm 
543034Sdougm static struct sa_proto_handle sa_proto_handle;
553034Sdougm 
563034Sdougm void proto_plugin_fini();
573034Sdougm 
583034Sdougm /*
593034Sdougm  * proto_plugin_init()
603034Sdougm  *
613034Sdougm  * Initialize the protocol specific plugin modules.
623034Sdougm  *
633034Sdougm  * Walk /usr/lib/fs/\* for libshare_*.so modules. That is,
643034Sdougm  * /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory
653034Sdougm  * would have a modules with name libshare_<proto>.so. If one is
663034Sdougm  * found, initialize it and add to the internal list of
673034Sdougm  * protocols. These are used for protocol specifici operations.
683034Sdougm  */
693034Sdougm 
703034Sdougm int
713034Sdougm proto_plugin_init()
723034Sdougm {
733034Sdougm 	struct sa_proto_plugin *proto;
743034Sdougm 	int num_protos = 0;
753034Sdougm 	int err;
763034Sdougm 	struct sa_plugin_ops *plugin_ops;
773034Sdougm 	void *dlhandle;
783034Sdougm 	DIR *dir;
793034Sdougm 	struct dirent *dent;
803034Sdougm 	int ret = SA_OK;
813034Sdougm 	struct stat st;
823034Sdougm 
833034Sdougm 	/*
843034Sdougm 	 * should walk "/usr/lib/fs/" for files of the form:
853034Sdougm 	 * libshare_*.so
863034Sdougm 	 */
873034Sdougm 	dir = opendir(SA_LIB_DIR);
883034Sdougm 	if (dir != NULL) {
893034Sdougm 	    while (ret == SA_OK && (dent = readdir(dir)) != NULL) {
903034Sdougm 		char path[MAXPATHLEN];
913910Sdougm 		char isa[MAXISALEN];
923910Sdougm 
933910Sdougm #if defined(_LP64)
943910Sdougm 		if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
953910Sdougm 		    isa[0] = '\0';
963910Sdougm #else
973910Sdougm 		isa[0] = '\0';
983910Sdougm #endif
993034Sdougm 		(void) snprintf(path, MAXPATHLEN,
1003910Sdougm 				"%s/%s/%s/libshare_%s.so.1",
1013910Sdougm 				SA_LIB_DIR,
1023910Sdougm 				dent->d_name,
1033910Sdougm 				isa,
1043910Sdougm 				dent->d_name);
1053910Sdougm 			if (stat(path, &st) < 0) {
1063034Sdougm 		    /* file doesn't exist, so don't try to map it */
1073034Sdougm 		    continue;
1083034Sdougm 		}
1093910Sdougm 		dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY);
1103034Sdougm 		if (dlhandle != NULL) {
1113034Sdougm 		    plugin_ops = (struct sa_plugin_ops *)
1123034Sdougm 					dlsym(dlhandle,	"sa_plugin_ops");
1133034Sdougm 		    proto = (struct sa_proto_plugin *)
1143034Sdougm 			calloc(1, sizeof (struct sa_proto_plugin));
1153034Sdougm 		    if (proto != NULL) {
1163034Sdougm 			proto->plugin_ops = plugin_ops;
1173034Sdougm 			proto->plugin_handle = dlhandle;
1183034Sdougm 			num_protos++;
1193034Sdougm 			proto->plugin_next = sap_proto_list;
1203034Sdougm 			sap_proto_list = proto;
1213034Sdougm 		    } else {
1223034Sdougm 			ret = SA_NO_MEMORY;
1233034Sdougm 		    }
1243034Sdougm 		} else {
1253034Sdougm 		    (void) fprintf(stderr,
1263407Sdougm 			    dgettext(TEXT_DOMAIN,
1273407Sdougm 				    "Error in plugin for protocol %s: %s\n"),
1283034Sdougm 			    dent->d_name, dlerror());
1293034Sdougm 		}
1303034Sdougm 	    }
1313034Sdougm 	    (void) closedir(dir);
1323034Sdougm 	}
1333034Sdougm 	if (ret == SA_OK) {
1343034Sdougm 	    sa_proto_handle.sa_proto =
1353034Sdougm 			(char **)calloc(num_protos, sizeof (char *));
1363034Sdougm 	    sa_proto_handle.sa_ops =
1373034Sdougm 			(struct sa_plugin_ops **)calloc(num_protos,
1383034Sdougm 					    sizeof (struct sa_plugin_ops *));
1393034Sdougm 	    if (sa_proto_handle.sa_proto != NULL &&
1403034Sdougm 		sa_proto_handle.sa_ops != NULL) {
1413034Sdougm 		int i;
1423034Sdougm 		struct sa_proto_plugin *tmp;
1433034Sdougm 		for (i = 0, tmp = sap_proto_list; i < num_protos;
1443034Sdougm 		    tmp = tmp->plugin_next) {
1453034Sdougm 		    err = 0;
1463034Sdougm 		    if (tmp->plugin_ops->sa_init != NULL)
1473034Sdougm 			err = tmp->plugin_ops->sa_init();
1483034Sdougm 		    if (err == SA_OK) {
1493034Sdougm 			/* only include if the init succeeded or was NULL */
1503034Sdougm 			sa_proto_handle.sa_num_proto++;
1513034Sdougm 			sa_proto_handle.sa_ops[i] = tmp->plugin_ops;
1523034Sdougm 			sa_proto_handle.sa_proto[i] =
1533034Sdougm 					tmp->plugin_ops->sa_protocol;
1543034Sdougm 			i++;
1553034Sdougm 		    }
1563034Sdougm 		}
1573034Sdougm 	    }
1583034Sdougm 	} else {
1593034Sdougm 	    /* there was an error, so cleanup prior to return of failure. */
1603034Sdougm 	    proto_plugin_fini();
1613034Sdougm 	}
1623034Sdougm 	return (ret);
1633034Sdougm }
1643034Sdougm 
1653034Sdougm /*
1663034Sdougm  * proto_plugin_fini()
1673034Sdougm  *
1683034Sdougm  * uninitialize all the plugin modules.
1693034Sdougm  */
1703034Sdougm 
1713034Sdougm void
1723034Sdougm proto_plugin_fini()
1733034Sdougm {
1743034Sdougm 	/*
1753034Sdougm 	 * free up all the protocols, calling their fini, if there is
1763034Sdougm 	 * one.
1773034Sdougm 	 */
1783034Sdougm 	while (sap_proto_list != NULL) {
1793034Sdougm 	    struct sa_proto_plugin *next;
1803034Sdougm 	    next = sap_proto_list->plugin_next;
1813034Sdougm 	    sap_proto_list->plugin_ops->sa_fini();
1823034Sdougm 	    if (sap_proto_list->plugin_handle != NULL)
1833034Sdougm 		(void) dlclose(sap_proto_list->plugin_handle);
1843034Sdougm 	    free(sap_proto_list);
1853034Sdougm 	    sap_proto_list = next;
1863034Sdougm 	}
1873034Sdougm 	if (sa_proto_handle.sa_ops != NULL) {
1883034Sdougm 	    free(sa_proto_handle.sa_ops);
1893034Sdougm 	    sa_proto_handle.sa_ops = NULL;
1903034Sdougm 	}
1913034Sdougm 	if (sa_proto_handle.sa_proto != NULL) {
1923034Sdougm 	    free(sa_proto_handle.sa_proto);
1933034Sdougm 	    sa_proto_handle.sa_proto = NULL;
1943034Sdougm 	}
1953034Sdougm 	sa_proto_handle.sa_num_proto = 0;
1963034Sdougm }
1973034Sdougm 
1983034Sdougm /*
1993034Sdougm  * find_protocol(proto)
2003034Sdougm  *
2013034Sdougm  * Search the plugin list for the specified protocol and return the
2023034Sdougm  * ops vector.  NULL if protocol is not defined.
2033034Sdougm  */
2043034Sdougm 
2053034Sdougm static struct sa_plugin_ops *
2063034Sdougm find_protocol(char *proto)
2073034Sdougm {
2083034Sdougm 	int i;
2093034Sdougm 
2103034Sdougm 	if (proto != NULL) {
2113034Sdougm 	    for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
2123034Sdougm 		if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0)
2133034Sdougm 		    return (sa_proto_handle.sa_ops[i]);
2143034Sdougm 	    }
2153034Sdougm 	}
2163034Sdougm 	return (NULL);
2173034Sdougm }
2183034Sdougm 
2193034Sdougm /*
2203034Sdougm  * sa_proto_share(proto, share)
2213034Sdougm  *
2223034Sdougm  * Activate a share for the specified protocol.
2233034Sdougm  */
2243034Sdougm 
2253034Sdougm int
2263034Sdougm sa_proto_share(char *proto, sa_share_t share)
2273034Sdougm {
2283034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
2293034Sdougm 	int ret = SA_INVALID_PROTOCOL;
2303034Sdougm 
2313034Sdougm 	if (ops != NULL && ops->sa_share != NULL)
2323034Sdougm 	    ret = ops->sa_share(share);
2333034Sdougm 	return (ret);
2343034Sdougm }
2353034Sdougm 
2363034Sdougm /*
2373034Sdougm  * sa_proto_unshare(proto, path)
2383034Sdougm  *
2393034Sdougm  * Deactivate (unshare) the path for this protocol.
2403034Sdougm  */
2413034Sdougm 
2423034Sdougm int
243*4543Smarks sa_proto_unshare(sa_share_t share, char *proto, char *path)
2443034Sdougm {
2453034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
2463034Sdougm 	int ret = SA_INVALID_PROTOCOL;
2473034Sdougm 
2483034Sdougm 	if (ops != NULL && ops->sa_unshare != NULL)
249*4543Smarks 	    ret = ops->sa_unshare(share, path);
2503034Sdougm 	return (ret);
2513034Sdougm }
2523034Sdougm 
2533034Sdougm /*
2543034Sdougm  * sa_proto_valid_prop(proto, prop, opt)
2553034Sdougm  *
2563034Sdougm  * check to see if the specified prop is valid for this protocol.
2573034Sdougm  */
2583034Sdougm 
2593034Sdougm int
2603034Sdougm sa_proto_valid_prop(char *proto, sa_property_t prop, sa_optionset_t opt)
2613034Sdougm {
2623034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
2633034Sdougm 	int ret = 0;
2643034Sdougm 
2653034Sdougm 	if (ops != NULL && ops->sa_valid_prop != NULL)
2663034Sdougm 	    ret = ops->sa_valid_prop(prop, opt);
2673034Sdougm 	return (ret);
2683034Sdougm }
2693034Sdougm 
2703034Sdougm /*
2713034Sdougm  * sa_proto_valid_space(proto, space)
2723034Sdougm  *
2733034Sdougm  * check if space is valid optionspace for proto.
2743034Sdougm  * Protocols that don't implement this don't support spaces.
2753034Sdougm  */
2763034Sdougm int
2773034Sdougm sa_proto_valid_space(char *proto, char *token)
2783034Sdougm {
2793034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
2803034Sdougm 	int ret = 0;
2813034Sdougm 
2823034Sdougm 	if (ops != NULL && ops->sa_valid_space != NULL)
2833034Sdougm 	    ret = ops->sa_valid_space(token);
2843034Sdougm 	return (ret);
2853034Sdougm }
2863034Sdougm 
2873034Sdougm /*
2883034Sdougm  * sa_proto_space_alias(proto, space)
2893034Sdougm  *
2903034Sdougm  * if the name for space is an alias, return its proper name.  This is
2913034Sdougm  * used to translate "default" values into proper form.
2923034Sdougm  */
2933034Sdougm char *
2943034Sdougm sa_proto_space_alias(char *proto, char *space)
2953034Sdougm {
2963034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
2973034Sdougm 	char *ret = space;
2983034Sdougm 
2993034Sdougm 	if (ops != NULL && ops->sa_space_alias != NULL)
3003034Sdougm 	    ret = ops->sa_space_alias(space);
3013034Sdougm 	return (ret);
3023034Sdougm }
3033034Sdougm 
3043034Sdougm /*
3053034Sdougm  * sa_proto_security_prop(proto, token)
3063034Sdougm  *
3073034Sdougm  * Check to see if the property name in token is a valid named
3083034Sdougm  * optionset property.
3093034Sdougm  */
3103034Sdougm 
3113034Sdougm int
3123034Sdougm sa_proto_security_prop(char *proto, char *token)
3133034Sdougm {
3143034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
3153034Sdougm 	int ret = 0;
3163034Sdougm 
3173034Sdougm 	if (ops != NULL && ops->sa_security_prop != NULL)
3183034Sdougm 	    ret = ops->sa_security_prop(token);
3193034Sdougm 	return (ret);
3203034Sdougm }
3213034Sdougm 
3223034Sdougm /*
3233034Sdougm  * sa_proto_legacy_opts(proto, grouup, options)
3243034Sdougm  *
3253034Sdougm  * Have the protocol specific parser parse the options string and add
3263034Sdougm  * an appropriate optionset to group.
3273034Sdougm  */
3283034Sdougm 
3293034Sdougm int
3303034Sdougm sa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
3313034Sdougm {
3323034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
3333034Sdougm 	int ret = SA_INVALID_PROTOCOL;
3343034Sdougm 
3353034Sdougm 	if (ops != NULL && ops->sa_legacy_opts != NULL)
3363034Sdougm 	    ret = ops->sa_legacy_opts(group, options);
3373034Sdougm 	return (ret);
3383034Sdougm }
3393034Sdougm 
3403034Sdougm /*
3413034Sdougm  * sa_proto_legacy_format(proto, group, hier)
3423034Sdougm  *
3433034Sdougm  * Return a legacy format string representing either the group's
3443034Sdougm  * properties or the groups hierarchical properties.
3453034Sdougm  */
3463034Sdougm 
3473034Sdougm char *
3483034Sdougm sa_proto_legacy_format(char *proto, sa_group_t group, int hier)
3493034Sdougm {
3503034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
3513034Sdougm 	char *ret = NULL;
3523034Sdougm 
3533034Sdougm 	if (ops != NULL && ops->sa_legacy_format != NULL)
3543034Sdougm 	    ret = ops->sa_legacy_format(group, hier);
3553034Sdougm 	return (ret);
3563034Sdougm }
3573034Sdougm 
3583034Sdougm void
3593034Sdougm sa_format_free(char *str)
3603034Sdougm {
3613034Sdougm 	free(str);
3623034Sdougm }
3633034Sdougm 
3643034Sdougm /*
3653034Sdougm  * sharectl related API functions
3663034Sdougm  */
3673034Sdougm 
3683034Sdougm /*
3693034Sdougm  * sa_proto_get_properties(proto)
3703034Sdougm  *
3713034Sdougm  * Return the set of properties that are specific to the
3723034Sdougm  * protocol. These are usually in /etc/dfs/<proto> and related files,
3733034Sdougm  * but only the protocol module knows which ones for sure.
3743034Sdougm  */
3753034Sdougm 
3763034Sdougm sa_protocol_properties_t
3773034Sdougm sa_proto_get_properties(char *proto)
3783034Sdougm {
3793034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
3803034Sdougm 	sa_protocol_properties_t props = NULL;
3813034Sdougm 
3823034Sdougm 	if (ops != NULL && ops->sa_get_proto_set != NULL)
3833034Sdougm 	    props = ops->sa_get_proto_set();
3843034Sdougm 	return (props);
3853034Sdougm }
3863034Sdougm 
3873034Sdougm /*
3883034Sdougm  * sa_proto_set_property(proto, prop)
3893034Sdougm  *
3903034Sdougm  * Update the protocol specifiec property.
3913034Sdougm  */
3923034Sdougm 
3933034Sdougm int
3943034Sdougm sa_proto_set_property(char *proto, sa_property_t prop)
3953034Sdougm {
3963034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
3973034Sdougm 	int ret = SA_OK;
3983034Sdougm 	if (ops != NULL && ops->sa_set_proto_prop != NULL)
3993034Sdougm 	    ret = ops->sa_set_proto_prop(prop);
4003034Sdougm 	return (ret);
4013034Sdougm }
4023034Sdougm 
4033034Sdougm /*
4043034Sdougm  * sa_valid_protocol(proto)
4053034Sdougm  *
4063034Sdougm  * check to see if the protocol specified is defined by a
4073034Sdougm  * plugin. Returns true (1) or false (0)
4083034Sdougm  */
4093034Sdougm 
4103034Sdougm int
4113034Sdougm sa_valid_protocol(char *proto)
4123034Sdougm {
4133034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
4143034Sdougm 	return (ops != NULL);
4153034Sdougm }
4163034Sdougm 
4173034Sdougm /*
4183034Sdougm  * Return the current operational status of the protocol
4193034Sdougm  */
4203034Sdougm 
4213034Sdougm char *
4223034Sdougm sa_get_protocol_status(char *proto)
4233034Sdougm {
4243034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
4253034Sdougm 	char *ret = NULL;
4263034Sdougm 	if (ops != NULL && ops->sa_get_proto_status != NULL)
4273034Sdougm 	    ret = ops->sa_get_proto_status(proto);
4283034Sdougm 	return (ret);
4293034Sdougm }
4303034Sdougm 
4313034Sdougm /*
4323034Sdougm  * sa_proto_update_legacy(proto, share)
4333034Sdougm  *
4343034Sdougm  * Update the protocol specific legacy files if necessary for the
4353034Sdougm  * specified share.
4363034Sdougm  */
4373034Sdougm 
4383034Sdougm int
4393034Sdougm sa_proto_update_legacy(char *proto, sa_share_t share)
4403034Sdougm {
4413034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
4423034Sdougm 	int ret = SA_NOT_IMPLEMENTED;
4433034Sdougm 
4443034Sdougm 	if (ops != NULL) {
4453034Sdougm 	    if (ops->sa_update_legacy != NULL)
4463034Sdougm 		ret = ops->sa_update_legacy(share);
4473034Sdougm 	}
4483034Sdougm 	return (ret);
4493034Sdougm }
4503034Sdougm 
4513034Sdougm /*
4523034Sdougm  * sa_delete_legacy(proto, share)
4533034Sdougm  *
4543034Sdougm  * remove the specified share from the protocol specific legacy files.
4553034Sdougm  */
4563034Sdougm 
4573034Sdougm int
4583034Sdougm sa_proto_delete_legacy(char *proto, sa_share_t share)
4593034Sdougm {
4603034Sdougm 	struct sa_plugin_ops *ops = find_protocol(proto);
4613034Sdougm 	int ret = SA_OK;
4623034Sdougm 
4633034Sdougm 	if (ops != NULL) {
4643034Sdougm 	    if (ops->sa_delete_legacy != NULL)
4653034Sdougm 		ret = ops->sa_delete_legacy(share);
4663034Sdougm 	} else {
4673034Sdougm 	    if (proto != NULL)
4683034Sdougm 		ret = SA_NOT_IMPLEMENTED;
4693034Sdougm 	    else
4703034Sdougm 		ret = SA_INVALID_PROTOCOL;
4713034Sdougm 	}
4723034Sdougm 	return (ret);
4733034Sdougm }
474