Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <libshare.h>
     31 #include "libshare_impl.h"
     32 #include <dlfcn.h>
     33 #include <link.h>
     34 #include <sys/types.h>
     35 #include <sys/param.h>
     36 #include <sys/stat.h>
     37 #include <dirent.h>
     38 #include <libintl.h>
     39 #include <sys/systeminfo.h>
     40 #include <thread.h>
     41 #include <synch.h>
     42 
     43 #define	MAXISALEN	257	/* based on sysinfo(2) man page */
     44 
     45 /*
     46  * protocol plugin interface
     47  *
     48  * finds plugins and makes them accessible. This is only "used" by
     49  * libshare.so.
     50  */
     51 
     52 struct sa_proto_plugin *sap_proto_list;
     53 
     54 static struct sa_proto_handle sa_proto_handle;
     55 
     56 void proto_plugin_fini();
     57 
     58 /*
     59  * Returns true if name is "." or "..", otherwise returns false.
     60  */
     61 static boolean_t
     62 proto_is_dot_or_dotdot(const char *name)
     63 {
     64 	if (*name != '.')
     65 		return (B_FALSE);
     66 
     67 	if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
     68 		return (B_TRUE);
     69 
     70 	return (B_FALSE);
     71 }
     72 
     73 /*
     74  * proto_plugin_init()
     75  *
     76  * Initialize the protocol specific plugin modules.
     77  *
     78  * Walk /usr/lib/fs/\* for libshare_*.so modules, for example,
     79  * /usr/lib/fs/nfs/libshare_nfs.so. A protocol specific directory
     80  * would have modules with names of the form libshare_<proto>.so.
     81  * For each protocol found, initialize it and add it to the internal
     82  * list of protocols. These are used for protocol specific operations.
     83  */
     84 
     85 int
     86 proto_plugin_init()
     87 {
     88 	struct sa_proto_plugin *proto;
     89 	int num_protos = 0;
     90 	struct sa_plugin_ops *plugin_ops;
     91 	void *dlhandle;
     92 	DIR *dir;
     93 	struct dirent *dent;
     94 	int ret = SA_OK;
     95 	struct stat st;
     96 	char isa[MAXISALEN];
     97 
     98 #if defined(_LP64)
     99 	if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
    100 		isa[0] = '\0';
    101 #else
    102 	isa[0] = '\0';
    103 #endif
    104 
    105 	if ((dir = opendir(SA_LIB_DIR)) == NULL)
    106 		return (SA_OK);
    107 
    108 	while ((dent = readdir(dir)) != NULL) {
    109 		char path[MAXPATHLEN];
    110 
    111 		if (proto_is_dot_or_dotdot(dent->d_name))
    112 			continue;
    113 
    114 		(void) snprintf(path, MAXPATHLEN,
    115 		    "%s/%s/%s/libshare_%s.so.1", SA_LIB_DIR,
    116 		    dent->d_name, isa, dent->d_name);
    117 
    118 		/*
    119 		 * If file doesn't exist, don't try to map it
    120 		 */
    121 		if (stat(path, &st) < 0)
    122 			continue;
    123 
    124 		if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL) {
    125 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
    126 			    "Error in plugin for protocol %s: %s\n"),
    127 			    dent->d_name, dlerror());
    128 			continue;
    129 		}
    130 
    131 		plugin_ops = (struct sa_plugin_ops *)
    132 		    dlsym(dlhandle, "sa_plugin_ops");
    133 		if (plugin_ops == NULL) {
    134 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
    135 			    "Error in plugin ops for protocol %s: %s\n"),
    136 			    dent->d_name, dlerror());
    137 			(void) dlclose(dlhandle);
    138 			continue;
    139 		}
    140 
    141 		proto = (struct sa_proto_plugin *)
    142 		    calloc(1, sizeof (struct sa_proto_plugin));
    143 		if (proto == NULL) {
    144 			(void) dlclose(dlhandle);
    145 			ret = SA_NO_MEMORY;
    146 			continue;
    147 		}
    148 
    149 		proto->plugin_ops = plugin_ops;
    150 		proto->plugin_handle = dlhandle;
    151 		num_protos++;
    152 		proto->plugin_next = sap_proto_list;
    153 		sap_proto_list = proto;
    154 	}
    155 
    156 	(void) closedir(dir);
    157 
    158 	if (num_protos != 0) {
    159 		sa_proto_handle.sa_proto =
    160 		    (char **)calloc(num_protos, sizeof (char *));
    161 		sa_proto_handle.sa_ops =
    162 		    (struct sa_plugin_ops **)calloc(num_protos,
    163 		    sizeof (struct sa_plugin_ops *));
    164 		if (sa_proto_handle.sa_proto != NULL &&
    165 		    sa_proto_handle.sa_ops != NULL) {
    166 			int i;
    167 			struct sa_proto_plugin *tmp;
    168 
    169 			for (i = 0, tmp = sap_proto_list;
    170 			    i < num_protos && tmp != NULL;
    171 			    tmp = tmp->plugin_next) {
    172 				int err;
    173 				err = SA_OK;
    174 				if (tmp->plugin_ops->sa_init != NULL)
    175 					err = tmp->plugin_ops->sa_init();
    176 				if (err == SA_OK) {
    177 					/*
    178 					 * Only include if the init
    179 					 * succeeded or was NULL
    180 					 */
    181 					sa_proto_handle.sa_num_proto++;
    182 					sa_proto_handle.sa_ops[i] =
    183 					    tmp->plugin_ops;
    184 					sa_proto_handle.sa_proto[i] =
    185 					    tmp->plugin_ops->sa_protocol;
    186 					i++;
    187 				}
    188 			}
    189 		} else {
    190 			ret = SA_NO_MEMORY;
    191 		}
    192 	}
    193 
    194 	/*
    195 	 * There was an error, so cleanup prior to return of failure.
    196 	 */
    197 	if (ret != SA_OK)
    198 		proto_plugin_fini();
    199 
    200 	return (ret);
    201 }
    202 
    203 /*
    204  * proto_plugin_fini()
    205  *
    206  * Uninitialize all the plugin modules.
    207  */
    208 
    209 void
    210 proto_plugin_fini()
    211 {
    212 	struct sa_proto_plugin *p;
    213 
    214 	/*
    215 	 * Protocols may call this framework during _fini
    216 	 * (the smbfs plugin is known to do this) so do
    217 	 * two passes: 1st call _fini; 2nd free, dlclose.
    218 	 */
    219 	for (p = sap_proto_list; p != NULL; p = p->plugin_next)
    220 		p->plugin_ops->sa_fini();
    221 
    222 	while ((p = sap_proto_list) != NULL) {
    223 		sap_proto_list = p->plugin_next;
    224 
    225 		if (p->plugin_handle != NULL)
    226 			(void) dlclose(p->plugin_handle);
    227 		free(p);
    228 	}
    229 	if (sa_proto_handle.sa_ops != NULL) {
    230 		free(sa_proto_handle.sa_ops);
    231 		sa_proto_handle.sa_ops = NULL;
    232 	}
    233 	if (sa_proto_handle.sa_proto != NULL) {
    234 		free(sa_proto_handle.sa_proto);
    235 		sa_proto_handle.sa_proto = NULL;
    236 	}
    237 	sa_proto_handle.sa_num_proto = 0;
    238 }
    239 
    240 /*
    241  * find_protocol(proto)
    242  *
    243  * Search the plugin list for the specified protocol and return the
    244  * ops vector.  NULL if protocol is not defined.
    245  */
    246 
    247 static struct sa_plugin_ops *
    248 find_protocol(char *proto)
    249 {
    250 	int i;
    251 	struct sa_plugin_ops *ops = NULL;
    252 	extern mutex_t sa_global_lock;
    253 
    254 	(void) mutex_lock(&sa_global_lock);
    255 	if (proto != NULL) {
    256 		for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
    257 			if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) {
    258 				ops = sa_proto_handle.sa_ops[i];
    259 				break;
    260 			}
    261 		}
    262 	}
    263 	(void) mutex_unlock(&sa_global_lock);
    264 	return (ops);
    265 }
    266 
    267 /*
    268  * sa_proto_share(proto, share)
    269  *
    270  * Activate a share for the specified protocol.
    271  */
    272 
    273 int
    274 sa_proto_share(char *proto, sa_share_t share)
    275 {
    276 	struct sa_plugin_ops *ops = find_protocol(proto);
    277 	int ret = SA_INVALID_PROTOCOL;
    278 
    279 	if (ops != NULL && ops->sa_share != NULL)
    280 		ret = ops->sa_share(share);
    281 	return (ret);
    282 }
    283 
    284 /*
    285  * sa_proto_unshare(proto, share)
    286  *
    287  * Deactivate (unshare) the share for this protocol.
    288  */
    289 
    290 int
    291 sa_proto_unshare(sa_share_t share, char *proto, char *path)
    292 {
    293 	struct sa_plugin_ops *ops = find_protocol(proto);
    294 	int ret = SA_INVALID_PROTOCOL;
    295 
    296 	if (ops != NULL && ops->sa_unshare != NULL)
    297 		ret = ops->sa_unshare(share, path);
    298 	return (ret);
    299 }
    300 
    301 /*
    302  * sa_proto_share_resource(char *proto, sa_resource_t resource)
    303  *
    304  * For protocols that actually enable at the resource level, do the
    305  * protocol specific resource enable. If it doesn't, return an error.
    306  * Note that the resource functions are optional so can return
    307  * SA_NOT_SUPPORTED.
    308  */
    309 
    310 int
    311 sa_proto_share_resource(char *proto, sa_resource_t resource)
    312 {
    313 	struct sa_plugin_ops *ops = find_protocol(proto);
    314 	int ret = SA_INVALID_PROTOCOL;
    315 
    316 	if (ops != NULL) {
    317 		if (ops->sa_enable_resource != NULL)
    318 			ret = ops->sa_enable_resource(resource);
    319 		else
    320 			ret = SA_NOT_SUPPORTED;
    321 	}
    322 	return (ret);
    323 }
    324 
    325 /*
    326  * sa_proto_unshare_resource(char *proto, sa_resource_t resource)
    327  *
    328  * For protocols that actually disable at the resource level, do the
    329  * protocol specific resource disable. If it doesn't, return an error.
    330  */
    331 
    332 int
    333 sa_proto_unshare_resource(char *proto, sa_resource_t resource)
    334 {
    335 	struct sa_plugin_ops *ops = find_protocol(proto);
    336 	int ret = SA_INVALID_PROTOCOL;
    337 
    338 	if (ops != NULL) {
    339 		if (ops->sa_disable_resource != NULL)
    340 			ret = ops->sa_disable_resource(resource);
    341 		else
    342 			ret = SA_NOT_SUPPORTED;
    343 	}
    344 	return (ret);
    345 }
    346 
    347 /*
    348  * sa_proto_valid_prop(handle, proto, prop, opt)
    349  *
    350  * Check to see if the specified prop is valid for this protocol.
    351  */
    352 
    353 int
    354 sa_proto_valid_prop(sa_handle_t handle, char *proto, sa_property_t prop,
    355     sa_optionset_t opt)
    356 {
    357 	struct sa_plugin_ops *ops = find_protocol(proto);
    358 	int ret = 0;
    359 
    360 	if (ops != NULL && ops->sa_valid_prop != NULL)
    361 		ret = ops->sa_valid_prop(handle, prop, opt);
    362 	return (ret);
    363 }
    364 
    365 /*
    366  * sa_proto_valid_space(proto, space)
    367  *
    368  * Check if space is valid optionspace for proto.
    369  * Protocols that don't implement this don't support spaces.
    370  */
    371 int
    372 sa_proto_valid_space(char *proto, char *token)
    373 {
    374 	struct sa_plugin_ops *ops = find_protocol(proto);
    375 	int ret = 0;
    376 
    377 	if (ops != NULL && ops->sa_valid_space != NULL)
    378 		ret = ops->sa_valid_space(token);
    379 	return (ret);
    380 }
    381 
    382 /*
    383  * sa_proto_space_alias(proto, space)
    384  *
    385  * If the name for space is an alias, return its proper name.  This is
    386  * used to translate "default" values into proper form.
    387  */
    388 char *
    389 sa_proto_space_alias(char *proto, char *space)
    390 {
    391 	struct sa_plugin_ops *ops = find_protocol(proto);
    392 	char *ret = space;
    393 
    394 	if (ops != NULL && ops->sa_space_alias != NULL)
    395 		ret = ops->sa_space_alias(space);
    396 	return (ret);
    397 }
    398 
    399 /*
    400  * sa_proto_security_prop(proto, token)
    401  *
    402  * Check to see if the property name in token is a valid named
    403  * optionset property.
    404  */
    405 
    406 int
    407 sa_proto_security_prop(char *proto, char *token)
    408 {
    409 	struct sa_plugin_ops *ops = find_protocol(proto);
    410 	int ret = 0;
    411 
    412 	if (ops != NULL && ops->sa_security_prop != NULL)
    413 		ret = ops->sa_security_prop(token);
    414 	return (ret);
    415 }
    416 
    417 /*
    418  * sa_proto_legacy_opts(proto, grouup, options)
    419  *
    420  * Have the protocol specific parser parse the options string and add
    421  * an appropriate optionset to group.
    422  */
    423 
    424 int
    425 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
    426 {
    427 	struct sa_plugin_ops *ops = find_protocol(proto);
    428 	int ret = SA_INVALID_PROTOCOL;
    429 
    430 	if (ops != NULL && ops->sa_legacy_opts != NULL)
    431 		ret = ops->sa_legacy_opts(group, options);
    432 	return (ret);
    433 }
    434 
    435 /*
    436  * sa_proto_legacy_format(proto, group, hier)
    437  *
    438  * Return a legacy format string representing either the group's
    439  * properties or the groups hierarchical properties.
    440  */
    441 
    442 char *
    443 sa_proto_legacy_format(char *proto, sa_group_t group, int hier)
    444 {
    445 	struct sa_plugin_ops *ops = find_protocol(proto);
    446 	char *ret = NULL;
    447 
    448 	if (ops != NULL && ops->sa_legacy_format != NULL)
    449 		ret = ops->sa_legacy_format(group, hier);
    450 	return (ret);
    451 }
    452 
    453 void
    454 sa_format_free(char *str)
    455 {
    456 	free(str);
    457 }
    458 
    459 /*
    460  * sharectl related API functions
    461  */
    462 
    463 /*
    464  * sa_proto_get_properties(proto)
    465  *
    466  * Return the set of properties that are specific to the
    467  * protocol. These are usually in /etc/dfs/<proto> and related files,
    468  * but only the protocol module knows which ones for sure.
    469  */
    470 
    471 sa_protocol_properties_t
    472 sa_proto_get_properties(char *proto)
    473 {
    474 	struct sa_plugin_ops *ops = find_protocol(proto);
    475 	sa_protocol_properties_t props = NULL;
    476 
    477 	if (ops != NULL && ops->sa_get_proto_set != NULL)
    478 		props = ops->sa_get_proto_set();
    479 	return (props);
    480 }
    481 
    482 /*
    483  * sa_proto_set_property(proto, prop)
    484  *
    485  * Update the protocol specific property.
    486  */
    487 
    488 int
    489 sa_proto_set_property(char *proto, sa_property_t prop)
    490 {
    491 	struct sa_plugin_ops *ops = find_protocol(proto);
    492 	int ret = SA_OK;
    493 
    494 	if (ops != NULL && ops->sa_set_proto_prop != NULL)
    495 		ret = ops->sa_set_proto_prop(prop);
    496 	return (ret);
    497 }
    498 
    499 /*
    500  * sa_valid_protocol(proto)
    501  *
    502  * Check to see if the protocol specified is defined by a
    503  * plugin. Returns true (1) or false (0)
    504  */
    505 
    506 int
    507 sa_valid_protocol(char *proto)
    508 {
    509 	struct sa_plugin_ops *ops = find_protocol(proto);
    510 	return (ops != NULL);
    511 }
    512 
    513 /*
    514  * Return the current operational status of the protocol
    515  */
    516 
    517 char *
    518 sa_get_protocol_status(char *proto)
    519 {
    520 	struct sa_plugin_ops *ops = find_protocol(proto);
    521 	char *ret = NULL;
    522 	if (ops != NULL && ops->sa_get_proto_status != NULL)
    523 		ret = ops->sa_get_proto_status(proto);
    524 	return (ret);
    525 }
    526 
    527 /*
    528  * sa_proto_update_legacy(proto, share)
    529  *
    530  * Update the protocol specific legacy files if necessary for the
    531  * specified share.
    532  */
    533 
    534 int
    535 sa_proto_update_legacy(char *proto, sa_share_t share)
    536 {
    537 	struct sa_plugin_ops *ops = find_protocol(proto);
    538 	int ret = SA_NOT_IMPLEMENTED;
    539 
    540 	if (ops != NULL) {
    541 		if (ops->sa_update_legacy != NULL)
    542 			ret = ops->sa_update_legacy(share);
    543 	}
    544 	return (ret);
    545 }
    546 
    547 /*
    548  * sa_delete_legacy(proto, share)
    549  *
    550  * Remove the specified share from the protocol specific legacy files.
    551  */
    552 
    553 int
    554 sa_proto_delete_legacy(char *proto, sa_share_t share)
    555 {
    556 	struct sa_plugin_ops *ops = find_protocol(proto);
    557 	int ret = SA_NOT_IMPLEMENTED;
    558 
    559 	if (ops != NULL) {
    560 		if (ops->sa_delete_legacy != NULL)
    561 			ret = ops->sa_delete_legacy(share);
    562 	} else {
    563 		if (proto != NULL)
    564 			ret = SA_NOT_IMPLEMENTED;
    565 		else
    566 			ret = SA_INVALID_PROTOCOL;
    567 	}
    568 	return (ret);
    569 }
    570 
    571 /*
    572  * sa_proto_delete_section(proto, section)
    573  *
    574  * Remove the specified section from the protocol specific legacy files,
    575  * if supported.
    576  */
    577 
    578 int
    579 sa_proto_delete_section(char *proto, char *section)
    580 {
    581 	struct sa_plugin_ops *ops = find_protocol(proto);
    582 	int ret = SA_OK;
    583 
    584 	if (ops != NULL) {
    585 		if (ops->sa_delete_proto_section != NULL)
    586 			ret = ops->sa_delete_proto_section(section);
    587 	} else {
    588 		if (proto != NULL)
    589 			ret = SA_NOT_IMPLEMENTED;
    590 		else
    591 			ret = SA_INVALID_PROTOCOL;
    592 	}
    593 	return (ret);
    594 }
    595 
    596 /*
    597  * sa_proto_change_notify(share, char *protocol)
    598  *
    599  * Notify the protocol that a change has been made to the share
    600  */
    601 
    602 int
    603 sa_proto_change_notify(sa_share_t share, char *proto)
    604 {
    605 	struct sa_plugin_ops *ops = find_protocol(proto);
    606 	int ret = SA_NOT_IMPLEMENTED;
    607 
    608 	if (ops != NULL) {
    609 		if (ops->sa_change_notify != NULL)
    610 			ret = ops->sa_change_notify(share);
    611 	} else	if (proto == NULL) {
    612 
    613 			ret = SA_INVALID_PROTOCOL;
    614 	}
    615 	return (ret);
    616 }
    617 
    618 /*
    619  * sa_proto_notify_resource(resource, char *protocol)
    620  *
    621  * Notify the protocol that a change has been made to the share
    622  */
    623 
    624 int
    625 sa_proto_notify_resource(sa_resource_t resource, char *proto)
    626 {
    627 	struct sa_plugin_ops *ops = find_protocol(proto);
    628 	int ret = SA_NOT_IMPLEMENTED;
    629 
    630 	if (ops != NULL) {
    631 		if (ops->sa_notify_resource != NULL)
    632 			ret = ops->sa_notify_resource(resource);
    633 	} else if (proto == NULL) {
    634 			ret = SA_INVALID_PROTOCOL;
    635 	}
    636 	return (ret);
    637 }
    638 
    639 /*
    640  * sa_proto_get_featureset(protocol)
    641  *
    642  * Get bitmask of defined features of the protocol. These are
    643  * primarily things like SA_FEATURE_RESOURCE (shares are by resource
    644  * name rather than path) and other operational features that affect
    645  * behavior.
    646  */
    647 
    648 uint64_t
    649 sa_proto_get_featureset(char *proto)
    650 {
    651 	struct sa_plugin_ops *ops = find_protocol(proto);
    652 	uint64_t ret = 0;
    653 
    654 	if (ops != NULL) {
    655 		if (ops->sa_features != NULL)
    656 			ret = ops->sa_features();
    657 	}
    658 	/* if not implemented, zero is valid */
    659 	return (ret);
    660 }
    661 
    662 /*
    663  * sa_proto_get_transients(sa_handle_t)
    664  *
    665  * Called to get any protocol specific transient shares.  NFS doesn't
    666  * use this since the info is in sharetab which is processed as a
    667  * common transient store.
    668  *
    669  * The protocol plugin should verify that the share isn't in the
    670  * repository and then add it as a transient.
    671  *
    672  * Not having an entry is not a problem. It returns 0 in that case.
    673  */
    674 
    675 int
    676 sa_proto_get_transients(sa_handle_t handle, char *proto)
    677 {
    678 	struct sa_plugin_ops *ops = find_protocol(proto);
    679 	int ret = 0;
    680 
    681 	if (ops != NULL) {
    682 		if (ops->sa_get_transient_shares != NULL)
    683 			ret = ops->sa_get_transient_shares(handle);
    684 	}
    685 	return (ret);
    686 }
    687 
    688 /*
    689  * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname)
    690  *
    691  * Protocols may need to know when a resource has changed names in
    692  * order to notify clients. This must be done "before" the name in the
    693  * resource has been changed. Not being implemented is not a problem.
    694  */
    695 
    696 int
    697 sa_proto_rename_resource(sa_handle_t handle, char *proto,
    698     sa_resource_t resource, char *newname)
    699 {
    700 	struct sa_plugin_ops *ops = find_protocol(proto);
    701 	int ret = SA_OK;
    702 
    703 	if (ops != NULL) {
    704 		if (ops->sa_rename_resource != NULL)
    705 			ret = ops->sa_rename_resource(handle, resource,
    706 			    newname);
    707 	}
    708 	return (ret);
    709 }
    710