xref: /illumos-gate/usr/src/lib/libshare/common/plugin.c (revision 687915e946710e354e302fa654bf53bf38b57cc6)
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 
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 && tmp != NULL;
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(handle, 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(sa_handle_t handle, char *proto, sa_property_t prop,
315     sa_optionset_t opt)
316 {
317 	struct sa_plugin_ops *ops = find_protocol(proto);
318 	int ret = 0;
319 
320 	if (ops != NULL && ops->sa_valid_prop != NULL)
321 		ret = ops->sa_valid_prop(handle, prop, opt);
322 	return (ret);
323 }
324 
325 /*
326  * sa_proto_valid_space(proto, space)
327  *
328  * Check if space is valid optionspace for proto.
329  * Protocols that don't implement this don't support spaces.
330  */
331 int
332 sa_proto_valid_space(char *proto, char *token)
333 {
334 	struct sa_plugin_ops *ops = find_protocol(proto);
335 	int ret = 0;
336 
337 	if (ops != NULL && ops->sa_valid_space != NULL)
338 		ret = ops->sa_valid_space(token);
339 	return (ret);
340 }
341 
342 /*
343  * sa_proto_space_alias(proto, space)
344  *
345  * If the name for space is an alias, return its proper name.  This is
346  * used to translate "default" values into proper form.
347  */
348 char *
349 sa_proto_space_alias(char *proto, char *space)
350 {
351 	struct sa_plugin_ops *ops = find_protocol(proto);
352 	char *ret = space;
353 
354 	if (ops != NULL && ops->sa_space_alias != NULL)
355 		ret = ops->sa_space_alias(space);
356 	return (ret);
357 }
358 
359 /*
360  * sa_proto_security_prop(proto, token)
361  *
362  * Check to see if the property name in token is a valid named
363  * optionset property.
364  */
365 
366 int
367 sa_proto_security_prop(char *proto, char *token)
368 {
369 	struct sa_plugin_ops *ops = find_protocol(proto);
370 	int ret = 0;
371 
372 	if (ops != NULL && ops->sa_security_prop != NULL)
373 		ret = ops->sa_security_prop(token);
374 	return (ret);
375 }
376 
377 /*
378  * sa_proto_legacy_opts(proto, grouup, options)
379  *
380  * Have the protocol specific parser parse the options string and add
381  * an appropriate optionset to group.
382  */
383 
384 int
385 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
386 {
387 	struct sa_plugin_ops *ops = find_protocol(proto);
388 	int ret = SA_INVALID_PROTOCOL;
389 
390 	if (ops != NULL && ops->sa_legacy_opts != NULL)
391 		ret = ops->sa_legacy_opts(group, options);
392 	return (ret);
393 }
394 
395 /*
396  * sa_proto_legacy_format(proto, group, hier)
397  *
398  * Return a legacy format string representing either the group's
399  * properties or the groups hierarchical properties.
400  */
401 
402 char *
403 sa_proto_legacy_format(char *proto, sa_group_t group, int hier)
404 {
405 	struct sa_plugin_ops *ops = find_protocol(proto);
406 	char *ret = NULL;
407 
408 	if (ops != NULL && ops->sa_legacy_format != NULL)
409 		ret = ops->sa_legacy_format(group, hier);
410 	return (ret);
411 }
412 
413 void
414 sa_format_free(char *str)
415 {
416 	free(str);
417 }
418 
419 /*
420  * sharectl related API functions
421  */
422 
423 /*
424  * sa_proto_get_properties(proto)
425  *
426  * Return the set of properties that are specific to the
427  * protocol. These are usually in /etc/dfs/<proto> and related files,
428  * but only the protocol module knows which ones for sure.
429  */
430 
431 sa_protocol_properties_t
432 sa_proto_get_properties(char *proto)
433 {
434 	struct sa_plugin_ops *ops = find_protocol(proto);
435 	sa_protocol_properties_t props = NULL;
436 
437 	if (ops != NULL && ops->sa_get_proto_set != NULL)
438 		props = ops->sa_get_proto_set();
439 	return (props);
440 }
441 
442 /*
443  * sa_proto_set_property(proto, prop)
444  *
445  * Update the protocol specific property.
446  */
447 
448 int
449 sa_proto_set_property(char *proto, sa_property_t prop)
450 {
451 	struct sa_plugin_ops *ops = find_protocol(proto);
452 	int ret = SA_OK;
453 
454 	if (ops != NULL && ops->sa_set_proto_prop != NULL)
455 		ret = ops->sa_set_proto_prop(prop);
456 	return (ret);
457 }
458 
459 /*
460  * sa_valid_protocol(proto)
461  *
462  * Check to see if the protocol specified is defined by a
463  * plugin. Returns true (1) or false (0)
464  */
465 
466 int
467 sa_valid_protocol(char *proto)
468 {
469 	struct sa_plugin_ops *ops = find_protocol(proto);
470 	return (ops != NULL);
471 }
472 
473 /*
474  * Return the current operational status of the protocol
475  */
476 
477 char *
478 sa_get_protocol_status(char *proto)
479 {
480 	struct sa_plugin_ops *ops = find_protocol(proto);
481 	char *ret = NULL;
482 	if (ops != NULL && ops->sa_get_proto_status != NULL)
483 		ret = ops->sa_get_proto_status(proto);
484 	return (ret);
485 }
486 
487 /*
488  * sa_proto_update_legacy(proto, share)
489  *
490  * Update the protocol specific legacy files if necessary for the
491  * specified share.
492  */
493 
494 int
495 sa_proto_update_legacy(char *proto, sa_share_t share)
496 {
497 	struct sa_plugin_ops *ops = find_protocol(proto);
498 	int ret = SA_NOT_IMPLEMENTED;
499 
500 	if (ops != NULL) {
501 		if (ops->sa_update_legacy != NULL)
502 			ret = ops->sa_update_legacy(share);
503 	}
504 	return (ret);
505 }
506 
507 /*
508  * sa_delete_legacy(proto, share)
509  *
510  * Remove the specified share from the protocol specific legacy files.
511  */
512 
513 int
514 sa_proto_delete_legacy(char *proto, sa_share_t share)
515 {
516 	struct sa_plugin_ops *ops = find_protocol(proto);
517 	int ret = SA_NOT_IMPLEMENTED;
518 
519 	if (ops != NULL) {
520 		if (ops->sa_delete_legacy != NULL)
521 			ret = ops->sa_delete_legacy(share);
522 	} else {
523 		if (proto != NULL)
524 			ret = SA_NOT_IMPLEMENTED;
525 		else
526 			ret = SA_INVALID_PROTOCOL;
527 	}
528 	return (ret);
529 }
530 
531 /*
532  * sa_proto_delete_section(proto, section)
533  *
534  * Remove the specified section from the protocol specific legacy files,
535  * if supported.
536  */
537 
538 int
539 sa_proto_delete_section(char *proto, char *section)
540 {
541 	struct sa_plugin_ops *ops = find_protocol(proto);
542 	int ret = SA_OK;
543 
544 	if (ops != NULL) {
545 		if (ops->sa_delete_proto_section != NULL)
546 			ret = ops->sa_delete_proto_section(section);
547 	} else {
548 		if (proto != NULL)
549 			ret = SA_NOT_IMPLEMENTED;
550 		else
551 			ret = SA_INVALID_PROTOCOL;
552 	}
553 	return (ret);
554 }
555 
556 /*
557  * sa_proto_change_notify(share, char *protocol)
558  *
559  * Notify the protocol that a change has been made to the share
560  */
561 
562 int
563 sa_proto_change_notify(sa_share_t share, char *proto)
564 {
565 	struct sa_plugin_ops *ops = find_protocol(proto);
566 	int ret = SA_NOT_IMPLEMENTED;
567 
568 	if (ops != NULL) {
569 		if (ops->sa_change_notify != NULL)
570 			ret = ops->sa_change_notify(share);
571 	} else	if (proto == NULL) {
572 
573 			ret = SA_INVALID_PROTOCOL;
574 	}
575 	return (ret);
576 }
577 
578 /*
579  * sa_proto_notify_resource(resource, char *protocol)
580  *
581  * Notify the protocol that a change has been made to the share
582  */
583 
584 int
585 sa_proto_notify_resource(sa_resource_t resource, char *proto)
586 {
587 	struct sa_plugin_ops *ops = find_protocol(proto);
588 	int ret = SA_NOT_IMPLEMENTED;
589 
590 	if (ops != NULL) {
591 		if (ops->sa_notify_resource != NULL)
592 			ret = ops->sa_notify_resource(resource);
593 	} else if (proto == NULL) {
594 			ret = SA_INVALID_PROTOCOL;
595 	}
596 	return (ret);
597 }
598 
599 /*
600  * sa_proto_get_featureset(protocol)
601  *
602  * Get bitmask of defined features of the protocol. These are
603  * primarily things like SA_FEATURE_RESOURCE (shares are by resource
604  * name rather than path) and other operational features that affect
605  * behavior.
606  */
607 
608 uint64_t
609 sa_proto_get_featureset(char *proto)
610 {
611 	struct sa_plugin_ops *ops = find_protocol(proto);
612 	uint64_t ret = 0;
613 
614 	if (ops != NULL) {
615 		if (ops->sa_features != NULL)
616 			ret = ops->sa_features();
617 	}
618 	/* if not implemented, zero is valid */
619 	return (ret);
620 }
621 
622 /*
623  * sa_proto_get_transients(sa_handle_t)
624  *
625  * Called to get any protocol specific transient shares.  NFS doesn't
626  * use this since the info is in sharetab which is processed as a
627  * common transient store.
628  *
629  * The protocol plugin should verify that the share isn't in the
630  * repository and then add it as a transient.
631  *
632  * Not having an entry is not a problem. It returns 0 in that case.
633  */
634 
635 int
636 sa_proto_get_transients(sa_handle_t handle, char *proto)
637 {
638 	struct sa_plugin_ops *ops = find_protocol(proto);
639 	int ret = 0;
640 
641 	if (ops != NULL) {
642 		if (ops->sa_get_transient_shares != NULL)
643 			ret = ops->sa_get_transient_shares(handle);
644 	}
645 	return (ret);
646 }
647 
648 /*
649  * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname)
650  *
651  * Protocols may need to know when a resource has changed names in
652  * order to notify clients. This must be done "before" the name in the
653  * resource has been changed. Not being implemented is not a problem.
654  */
655 
656 int
657 sa_proto_rename_resource(sa_handle_t handle, char *proto,
658     sa_resource_t resource, char *newname)
659 {
660 	struct sa_plugin_ops *ops = find_protocol(proto);
661 	int ret = SA_OK;
662 
663 	if (ops != NULL) {
664 		if (ops->sa_rename_resource != NULL)
665 			ret = ops->sa_rename_resource(handle, resource,
666 			    newname);
667 	}
668 	return (ret);
669 }
670