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