xref: /illumos-gate/usr/src/lib/libshare/common/plugin.c (revision 7247f8883be6bcac5fe4735b6f87f873387dbbef)
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 specifici 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, path)
246  *
247  * Deactivate (unshare) the path 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_valid_prop(proto, prop, opt)
263  *
264  * Check to see if the specified prop is valid for this protocol.
265  */
266 
267 int
268 sa_proto_valid_prop(char *proto, sa_property_t prop, sa_optionset_t opt)
269 {
270 	struct sa_plugin_ops *ops = find_protocol(proto);
271 	int ret = 0;
272 
273 	if (ops != NULL && ops->sa_valid_prop != NULL)
274 		ret = ops->sa_valid_prop(prop, opt);
275 	return (ret);
276 }
277 
278 /*
279  * sa_proto_valid_space(proto, space)
280  *
281  * Check if space is valid optionspace for proto.
282  * Protocols that don't implement this don't support spaces.
283  */
284 int
285 sa_proto_valid_space(char *proto, char *token)
286 {
287 	struct sa_plugin_ops *ops = find_protocol(proto);
288 	int ret = 0;
289 
290 	if (ops != NULL && ops->sa_valid_space != NULL)
291 		ret = ops->sa_valid_space(token);
292 	return (ret);
293 }
294 
295 /*
296  * sa_proto_space_alias(proto, space)
297  *
298  * If the name for space is an alias, return its proper name.  This is
299  * used to translate "default" values into proper form.
300  */
301 char *
302 sa_proto_space_alias(char *proto, char *space)
303 {
304 	struct sa_plugin_ops *ops = find_protocol(proto);
305 	char *ret = space;
306 
307 	if (ops != NULL && ops->sa_space_alias != NULL)
308 		ret = ops->sa_space_alias(space);
309 	return (ret);
310 }
311 
312 /*
313  * sa_proto_security_prop(proto, token)
314  *
315  * Check to see if the property name in token is a valid named
316  * optionset property.
317  */
318 
319 int
320 sa_proto_security_prop(char *proto, char *token)
321 {
322 	struct sa_plugin_ops *ops = find_protocol(proto);
323 	int ret = 0;
324 
325 	if (ops != NULL && ops->sa_security_prop != NULL)
326 		ret = ops->sa_security_prop(token);
327 	return (ret);
328 }
329 
330 /*
331  * sa_proto_legacy_opts(proto, grouup, options)
332  *
333  * Have the protocol specific parser parse the options string and add
334  * an appropriate optionset to group.
335  */
336 
337 int
338 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
339 {
340 	struct sa_plugin_ops *ops = find_protocol(proto);
341 	int ret = SA_INVALID_PROTOCOL;
342 
343 	if (ops != NULL && ops->sa_legacy_opts != NULL)
344 		ret = ops->sa_legacy_opts(group, options);
345 	return (ret);
346 }
347 
348 /*
349  * sa_proto_legacy_format(proto, group, hier)
350  *
351  * Return a legacy format string representing either the group's
352  * properties or the groups hierarchical properties.
353  */
354 
355 char *
356 sa_proto_legacy_format(char *proto, sa_group_t group, int hier)
357 {
358 	struct sa_plugin_ops *ops = find_protocol(proto);
359 	char *ret = NULL;
360 
361 	if (ops != NULL && ops->sa_legacy_format != NULL)
362 		ret = ops->sa_legacy_format(group, hier);
363 	return (ret);
364 }
365 
366 void
367 sa_format_free(char *str)
368 {
369 	free(str);
370 }
371 
372 /*
373  * sharectl related API functions
374  */
375 
376 /*
377  * sa_proto_get_properties(proto)
378  *
379  * Return the set of properties that are specific to the
380  * protocol. These are usually in /etc/dfs/<proto> and related files,
381  * but only the protocol module knows which ones for sure.
382  */
383 
384 sa_protocol_properties_t
385 sa_proto_get_properties(char *proto)
386 {
387 	struct sa_plugin_ops *ops = find_protocol(proto);
388 	sa_protocol_properties_t props = NULL;
389 
390 	if (ops != NULL && ops->sa_get_proto_set != NULL)
391 		props = ops->sa_get_proto_set();
392 	return (props);
393 }
394 
395 /*
396  * sa_proto_set_property(proto, prop)
397  *
398  * Update the protocol specifiec property.
399  */
400 
401 int
402 sa_proto_set_property(char *proto, sa_property_t prop)
403 {
404 	struct sa_plugin_ops *ops = find_protocol(proto);
405 	int ret = SA_OK;
406 
407 	if (ops != NULL && ops->sa_set_proto_prop != NULL)
408 		ret = ops->sa_set_proto_prop(prop);
409 	return (ret);
410 }
411 
412 /*
413  * sa_valid_protocol(proto)
414  *
415  * Check to see if the protocol specified is defined by a
416  * plugin. Returns true (1) or false (0)
417  */
418 
419 int
420 sa_valid_protocol(char *proto)
421 {
422 	struct sa_plugin_ops *ops = find_protocol(proto);
423 	return (ops != NULL);
424 }
425 
426 /*
427  * Return the current operational status of the protocol
428  */
429 
430 char *
431 sa_get_protocol_status(char *proto)
432 {
433 	struct sa_plugin_ops *ops = find_protocol(proto);
434 	char *ret = NULL;
435 	if (ops != NULL && ops->sa_get_proto_status != NULL)
436 		ret = ops->sa_get_proto_status(proto);
437 	return (ret);
438 }
439 
440 /*
441  * sa_proto_update_legacy(proto, share)
442  *
443  * Update the protocol specific legacy files if necessary for the
444  * specified share.
445  */
446 
447 int
448 sa_proto_update_legacy(char *proto, sa_share_t share)
449 {
450 	struct sa_plugin_ops *ops = find_protocol(proto);
451 	int ret = SA_NOT_IMPLEMENTED;
452 
453 	if (ops != NULL) {
454 		if (ops->sa_update_legacy != NULL)
455 			ret = ops->sa_update_legacy(share);
456 	}
457 	return (ret);
458 }
459 
460 /*
461  * sa_delete_legacy(proto, share)
462  *
463  * Remove the specified share from the protocol specific legacy files.
464  */
465 
466 int
467 sa_proto_delete_legacy(char *proto, sa_share_t share)
468 {
469 	struct sa_plugin_ops *ops = find_protocol(proto);
470 	int ret = SA_OK;
471 
472 	if (ops != NULL) {
473 		if (ops->sa_delete_legacy != NULL)
474 			ret = ops->sa_delete_legacy(share);
475 	} else {
476 		if (proto != NULL)
477 			ret = SA_NOT_IMPLEMENTED;
478 		else
479 			ret = SA_INVALID_PROTOCOL;
480 	}
481 	return (ret);
482 }
483