xref: /illumos-gate/usr/src/lib/libshare/common/plugin.c (revision 24424a35444c8487648be681d47bee4f57af0ffc)
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 
42 /*
43  * protocol plugin interface
44  *
45  * finds plugins and makes them accessible. This is only "used" by
46  * libshare.so.
47  */
48 
49 struct sa_proto_plugin *sap_proto_list;
50 
51 static struct sa_proto_handle sa_proto_handle;
52 
53 void proto_plugin_fini();
54 
55 /*
56  * proto_plugin_init()
57  *
58  * Initialize the protocol specific plugin modules.
59  *
60  * Walk /usr/lib/fs/\* for libshare_*.so modules. That is,
61  * /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory
62  * would have a modules with name libshare_<proto>.so. If one is
63  * found, initialize it and add to the internal list of
64  * protocols. These are used for protocol specifici operations.
65  */
66 
67 int
68 proto_plugin_init()
69 {
70 	struct sa_proto_plugin *proto;
71 	int num_protos = 0;
72 	int err;
73 	struct sa_plugin_ops *plugin_ops;
74 	void *dlhandle;
75 	DIR *dir;
76 	struct dirent *dent;
77 	int ret = SA_OK;
78 	struct stat st;
79 
80 	/*
81 	 * should walk "/usr/lib/fs/" for files of the form:
82 	 * libshare_*.so
83 	 */
84 	dir = opendir(SA_LIB_DIR);
85 	if (dir != NULL) {
86 	    while (ret == SA_OK && (dent = readdir(dir)) != NULL) {
87 		char path[MAXPATHLEN];
88 		(void) snprintf(path, MAXPATHLEN,
89 				"%s/%s/libshare_%s.so",	SA_LIB_DIR,
90 				dent->d_name, dent->d_name);
91 		if (stat(path, &st) < 0) {
92 		    /* file doesn't exist, so don't try to map it */
93 		    continue;
94 		}
95 		dlhandle = dlopen(path, RTLD_NOW|RTLD_GLOBAL|RTLD_WORLD);
96 		if (dlhandle != NULL) {
97 		    plugin_ops = (struct sa_plugin_ops *)
98 					dlsym(dlhandle,	"sa_plugin_ops");
99 		    proto = (struct sa_proto_plugin *)
100 			calloc(1, sizeof (struct sa_proto_plugin));
101 		    if (proto != NULL) {
102 			proto->plugin_ops = plugin_ops;
103 			proto->plugin_handle = dlhandle;
104 			num_protos++;
105 			proto->plugin_next = sap_proto_list;
106 			sap_proto_list = proto;
107 		    } else {
108 			ret = SA_NO_MEMORY;
109 		    }
110 		} else {
111 		    (void) fprintf(stderr,
112 			    dgettext(TEXT_DOMAIN,
113 				    "Error in plugin for protocol %s: %s\n"),
114 			    dent->d_name, dlerror());
115 		}
116 	    }
117 	    (void) closedir(dir);
118 	}
119 	if (ret == SA_OK) {
120 	    sa_proto_handle.sa_proto =
121 			(char **)calloc(num_protos, sizeof (char *));
122 	    sa_proto_handle.sa_ops =
123 			(struct sa_plugin_ops **)calloc(num_protos,
124 					    sizeof (struct sa_plugin_ops *));
125 	    if (sa_proto_handle.sa_proto != NULL &&
126 		sa_proto_handle.sa_ops != NULL) {
127 		int i;
128 		struct sa_proto_plugin *tmp;
129 		for (i = 0, tmp = sap_proto_list; i < num_protos;
130 		    tmp = tmp->plugin_next) {
131 		    err = 0;
132 		    if (tmp->plugin_ops->sa_init != NULL)
133 			err = tmp->plugin_ops->sa_init();
134 		    if (err == SA_OK) {
135 			/* only include if the init succeeded or was NULL */
136 			sa_proto_handle.sa_num_proto++;
137 			sa_proto_handle.sa_ops[i] = tmp->plugin_ops;
138 			sa_proto_handle.sa_proto[i] =
139 					tmp->plugin_ops->sa_protocol;
140 			i++;
141 		    }
142 		}
143 	    }
144 	} else {
145 	    /* there was an error, so cleanup prior to return of failure. */
146 	    proto_plugin_fini();
147 	}
148 	return (ret);
149 }
150 
151 /*
152  * proto_plugin_fini()
153  *
154  * uninitialize all the plugin modules.
155  */
156 
157 void
158 proto_plugin_fini()
159 {
160 	/*
161 	 * free up all the protocols, calling their fini, if there is
162 	 * one.
163 	 */
164 	while (sap_proto_list != NULL) {
165 	    struct sa_proto_plugin *next;
166 	    next = sap_proto_list->plugin_next;
167 	    sap_proto_list->plugin_ops->sa_fini();
168 	    if (sap_proto_list->plugin_handle != NULL)
169 		(void) dlclose(sap_proto_list->plugin_handle);
170 	    free(sap_proto_list);
171 	    sap_proto_list = next;
172 	}
173 	if (sa_proto_handle.sa_ops != NULL) {
174 	    free(sa_proto_handle.sa_ops);
175 	    sa_proto_handle.sa_ops = NULL;
176 	}
177 	if (sa_proto_handle.sa_proto != NULL) {
178 	    free(sa_proto_handle.sa_proto);
179 	    sa_proto_handle.sa_proto = NULL;
180 	}
181 	sa_proto_handle.sa_num_proto = 0;
182 }
183 
184 /*
185  * find_protocol(proto)
186  *
187  * Search the plugin list for the specified protocol and return the
188  * ops vector.  NULL if protocol is not defined.
189  */
190 
191 static struct sa_plugin_ops *
192 find_protocol(char *proto)
193 {
194 	int i;
195 
196 	if (proto != NULL) {
197 	    for (i = 0; i < sa_proto_handle.sa_num_proto; i++) {
198 		if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0)
199 		    return (sa_proto_handle.sa_ops[i]);
200 	    }
201 	}
202 	return (NULL);
203 }
204 
205 /*
206  * sa_proto_share(proto, share)
207  *
208  * Activate a share for the specified protocol.
209  */
210 
211 int
212 sa_proto_share(char *proto, sa_share_t share)
213 {
214 	struct sa_plugin_ops *ops = find_protocol(proto);
215 	int ret = SA_INVALID_PROTOCOL;
216 
217 	if (ops != NULL && ops->sa_share != NULL)
218 	    ret = ops->sa_share(share);
219 	return (ret);
220 }
221 
222 /*
223  * sa_proto_unshare(proto, path)
224  *
225  * Deactivate (unshare) the path for this protocol.
226  */
227 
228 int
229 sa_proto_unshare(char *proto, char *path)
230 {
231 	struct sa_plugin_ops *ops = find_protocol(proto);
232 	int ret = SA_INVALID_PROTOCOL;
233 
234 	if (ops != NULL && ops->sa_unshare != NULL)
235 	    ret = ops->sa_unshare(path);
236 	return (ret);
237 }
238 
239 /*
240  * sa_proto_valid_prop(proto, prop, opt)
241  *
242  * check to see if the specified prop is valid for this protocol.
243  */
244 
245 int
246 sa_proto_valid_prop(char *proto, sa_property_t prop, sa_optionset_t opt)
247 {
248 	struct sa_plugin_ops *ops = find_protocol(proto);
249 	int ret = 0;
250 
251 	if (ops != NULL && ops->sa_valid_prop != NULL)
252 	    ret = ops->sa_valid_prop(prop, opt);
253 	return (ret);
254 }
255 
256 /*
257  * sa_proto_valid_space(proto, space)
258  *
259  * check if space is valid optionspace for proto.
260  * Protocols that don't implement this don't support spaces.
261  */
262 int
263 sa_proto_valid_space(char *proto, char *token)
264 {
265 	struct sa_plugin_ops *ops = find_protocol(proto);
266 	int ret = 0;
267 
268 	if (ops != NULL && ops->sa_valid_space != NULL)
269 	    ret = ops->sa_valid_space(token);
270 	return (ret);
271 }
272 
273 /*
274  * sa_proto_space_alias(proto, space)
275  *
276  * if the name for space is an alias, return its proper name.  This is
277  * used to translate "default" values into proper form.
278  */
279 char *
280 sa_proto_space_alias(char *proto, char *space)
281 {
282 	struct sa_plugin_ops *ops = find_protocol(proto);
283 	char *ret = space;
284 
285 	if (ops != NULL && ops->sa_space_alias != NULL)
286 	    ret = ops->sa_space_alias(space);
287 	return (ret);
288 }
289 
290 /*
291  * sa_proto_security_prop(proto, token)
292  *
293  * Check to see if the property name in token is a valid named
294  * optionset property.
295  */
296 
297 int
298 sa_proto_security_prop(char *proto, char *token)
299 {
300 	struct sa_plugin_ops *ops = find_protocol(proto);
301 	int ret = 0;
302 
303 	if (ops != NULL && ops->sa_security_prop != NULL)
304 	    ret = ops->sa_security_prop(token);
305 	return (ret);
306 }
307 
308 /*
309  * sa_proto_legacy_opts(proto, grouup, options)
310  *
311  * Have the protocol specific parser parse the options string and add
312  * an appropriate optionset to group.
313  */
314 
315 int
316 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options)
317 {
318 	struct sa_plugin_ops *ops = find_protocol(proto);
319 	int ret = SA_INVALID_PROTOCOL;
320 
321 	if (ops != NULL && ops->sa_legacy_opts != NULL)
322 	    ret = ops->sa_legacy_opts(group, options);
323 	return (ret);
324 }
325 
326 /*
327  * sa_proto_legacy_format(proto, group, hier)
328  *
329  * Return a legacy format string representing either the group's
330  * properties or the groups hierarchical properties.
331  */
332 
333 char *
334 sa_proto_legacy_format(char *proto, sa_group_t group, int hier)
335 {
336 	struct sa_plugin_ops *ops = find_protocol(proto);
337 	char *ret = NULL;
338 
339 	if (ops != NULL && ops->sa_legacy_format != NULL)
340 	    ret = ops->sa_legacy_format(group, hier);
341 	return (ret);
342 }
343 
344 void
345 sa_format_free(char *str)
346 {
347 	free(str);
348 }
349 
350 /*
351  * sharectl related API functions
352  */
353 
354 /*
355  * sa_proto_get_properties(proto)
356  *
357  * Return the set of properties that are specific to the
358  * protocol. These are usually in /etc/dfs/<proto> and related files,
359  * but only the protocol module knows which ones for sure.
360  */
361 
362 sa_protocol_properties_t
363 sa_proto_get_properties(char *proto)
364 {
365 	struct sa_plugin_ops *ops = find_protocol(proto);
366 	sa_protocol_properties_t props = NULL;
367 
368 	if (ops != NULL && ops->sa_get_proto_set != NULL)
369 	    props = ops->sa_get_proto_set();
370 	return (props);
371 }
372 
373 /*
374  * sa_proto_set_property(proto, prop)
375  *
376  * Update the protocol specifiec property.
377  */
378 
379 int
380 sa_proto_set_property(char *proto, sa_property_t prop)
381 {
382 	struct sa_plugin_ops *ops = find_protocol(proto);
383 	int ret = SA_OK;
384 	if (ops != NULL && ops->sa_set_proto_prop != NULL)
385 	    ret = ops->sa_set_proto_prop(prop);
386 	return (ret);
387 }
388 
389 /*
390  * sa_valid_protocol(proto)
391  *
392  * check to see if the protocol specified is defined by a
393  * plugin. Returns true (1) or false (0)
394  */
395 
396 int
397 sa_valid_protocol(char *proto)
398 {
399 	struct sa_plugin_ops *ops = find_protocol(proto);
400 	return (ops != NULL);
401 }
402 
403 /*
404  * Return the current operational status of the protocol
405  */
406 
407 char *
408 sa_get_protocol_status(char *proto)
409 {
410 	struct sa_plugin_ops *ops = find_protocol(proto);
411 	char *ret = NULL;
412 	if (ops != NULL && ops->sa_get_proto_status != NULL)
413 	    ret = ops->sa_get_proto_status(proto);
414 	return (ret);
415 }
416 
417 /*
418  * sa_proto_update_legacy(proto, share)
419  *
420  * Update the protocol specific legacy files if necessary for the
421  * specified share.
422  */
423 
424 int
425 sa_proto_update_legacy(char *proto, sa_share_t share)
426 {
427 	struct sa_plugin_ops *ops = find_protocol(proto);
428 	int ret = SA_NOT_IMPLEMENTED;
429 
430 	if (ops != NULL) {
431 	    if (ops->sa_update_legacy != NULL)
432 		ret = ops->sa_update_legacy(share);
433 	}
434 	return (ret);
435 }
436 
437 /*
438  * sa_delete_legacy(proto, share)
439  *
440  * remove the specified share from the protocol specific legacy files.
441  */
442 
443 int
444 sa_proto_delete_legacy(char *proto, sa_share_t share)
445 {
446 	struct sa_plugin_ops *ops = find_protocol(proto);
447 	int ret = SA_OK;
448 
449 	if (ops != NULL) {
450 	    if (ops->sa_delete_legacy != NULL)
451 		ret = ops->sa_delete_legacy(share);
452 	} else {
453 	    if (proto != NULL)
454 		ret = SA_NOT_IMPLEMENTED;
455 	    else
456 		ret = SA_INVALID_PROTOCOL;
457 	}
458 	return (ret);
459 }
460