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